How can I retrieve name(Key) of applied template? - c#

I have a template assigned to a button:
<Button x:Name="btn_PatMat" Template="{StaticResource PatMat_Button}" ...
How can I retrieve the Key/String/Name of this template from said button?
Pseudocode:
String = btn_PatMat.Template.???.ToString()

You can't. At least not in the way you're trying.
To quote from this SO post about x:Key (emphasis mine):
x:Key is used for items that are being added as values to a
dictionary, most often for styles and other resources that are being
added to a ResourceDictionary. When setting the x:Key attribute,
there is actually no corresponding property on the object or even an
attached dependency property being set. It is simply used by the
XAML processor to know what key to use when calling Dictionary.Add.
StaticResources are evaluated during loading, so once the control loads, the Template property is no longer set to a binding, but is instead set to a copy of the ControlTemplate from your Resources, and no corresponding property on that object is set to the key.
You can verify this by checking out the XAML of the button after it's loaded, by using something like XamlWriter.Save to view it's XAML string.
The only solution I can think of that might work would be to loop through your .Resources, and find a ControlTemplate that is equal to your Button's ControlTemplate. I haven't tested this, and it probably isn't very practical for large resource libraries, but it may be an option.
But a better solution would probably be to change your logic so the key value can be accessed some other way by whatever object needs it.

Well I'm afraid that's not possible because it's not intended by WPF. There are some people which wanted to get access to x:Name which is similar to x:Key, they all had to give up.
Pls have a look at this SO post and this additional link.
The only workaround I could imagine is reading all templates from the ResourceDictionary, instantiate each resource (if possible), find the template (if it's e.g. a style) and compare it with the current instance of the template found in the control. But this seems to be a pretty ugly solution and I'm not sure if it'll work without any problems.

Related

Load .xaml file and edit object tree at runtime

After reading into XamlWriter and XamlReader, I was wondering if it is possible to load an arbitrary .xaml file at runtime, edit the object tree and then reuse it again.
What I am trying to create is a kind of showcase application for all available styles of a project. I've got TemplateViews for several ControlTypes (such as ButtonTemplateView.xaml, ListboxTemplateView.xaml ...), with their Style property bound to a viewmodel, which get dynamically constructed for each fitting style at runtime and then added to the main view.
But I also want to show all styles for the CustomControls of the project, which right now I am doing via Activator.CreatInstance with the TargetTypeof the style, and then adding the object to the main view.
Now, lets say if a CustomControl MyCustomTextBox is based on a TextBox, can I just load the TextBoxTemplateView.xaml, switch every <TextBox ... /> to a <MyCustomTextBox .../> and then add it to my main view?
If so, how? Can I turn it into a string and just replace the words and then turn it back into something usable? Or do I have to edit the UserControl object I get when I use XamlReader.Load? Or something else?
I hope this is not a duplicate question (at least I didnt find anything like it) and thanks for any help in advance.
You could either replace all occurances of <TextBox> with <local:MyCustomTextBox> in the string that you pass to the XamlReader.Load method. This is probably the easiest way because then the XamlReader will create the MyCustomTextBox elements for you.
The other option would be to iterate through the <TextBox> elements in the UserControl that is returned from the XamlReader.Load method and replace these by MyCustomTextBox elements. How to do this depends on where the controls are located in the element tree of the UserControl.

Is it possible to bind to a property name?

Is it possible to bind a property name. I seem to come up with run time errors when I try.
For instance:
<button Name="{Binding UniqueID}" Click="ButtonHandler">
This being in a header for a collection in a grid-view...
You can't bind Name, sorry. It's used for too many things internally and stuff would surely go crazy if you could. The docs are a bit vague, but do say this: (emphasis mine)
You cannot use the string value of Name as a
direct source value for a data binding source. If you have to display
the same string value as Name in UI with binding, you should replicate
the same value to the Tag property, which can be used as a property
binding source. Also don't use Name as a binding target.
(MSDN: FrameworkElement.Name)
However, if you want to attach random extra data to UI controls, I would recommend using attached properties instead. That way they're specifically associated with what you're doing and will be appropriately typed, unlike Tag.
(MSDN: Custom Attached Properties)
Well, I've read the documentation over and over and cannot find a way to make it work. The documentation doesn't say you cannot do it, but it doesn't say you can do it either.
However, I found two workarounds. Instead of binding the name, if you aren't using Tag or DataContect, you can find to those and in the handler extract them by casting as a string.
It's not elegant, but, it does seem to work as expected.

How do you load the default template for an object in WPF?

The title is pretty self-explanatory. I cannot for the life of me, figure out how to load the default template for a particular object from within a DataTemplateSelector.
I know you're gunna ask. Why the heck would you need to do this? WPF will select that template for you if you bind the object to something!
Well, the short answer is: I need to make sure that every DataTemplate that gets returned is a new instance of the template. The control I have this template bound to is reusing it. I am trying to use x:Shared="False" but the control itself doesn't try to obtain the resource again, it's just reusing the one it already has. However, when I use a DataTemplateSelector, the SelectTemplate function get's called each time it requests a fresh UI. So if I can ensure that the DataTemplate being returned here is a new instance, everything should be great.
Except, as long as I am using a default template (ex, no x:Key="" attribute).
I don't know how to acquire that resource.
Thanks.

Implement binding extension on a property

I have a control that we could identify as similar to ListBox control. Each item is represented with one element (example TextBlock). What i would like is to change the layout of this item, so that it contains two TextBlocks. So I create a ControlTemplate, put a Border Grid, TwoTextBlocks, and all is well. Now the problem:
I need to be able to localize the text in the item, and I did this normally like this:
<... Text="{Binding Strings.SomeString, Source={StaticResource ApplicationResources}}" />
Now I need to be able to do the same with both TextBlocks. So i thought I need to create a custom type that this item will bind to, and expose two propertiws: Title and Description. If I expose this properties as string type, everything works ok, but I am loosing markup binding that I used previously. How to achieve the same with two properties? The result should be like:
<... Title="{Binding Strings.SomeString, Source={StaticResource ApplicationResources}}", Description="{Binding Strings.AnotherString, Source={StaticResource ApplicationResources}}" />
I was able to make Localization work with ResourcemManager class, but it gets even complicated in order to provide localization to be applied dynamically at runtime.
So, what do I need to do to be able to use above code? Then I just need to implement INotifyPropertyChanged on ApplicationResource and all is set.
Great!
I'm going to do the same thing you did here. Yeah, I have a solution but I'm not sure if it works till now.
First, we need a LocalizationManager which holds a dictionary.
For example, if you need to localize a user account window, just do this
<TextBlock Text="something, UsernameKey">
And the localizationManager will map UsernameKey to "Username" or other language
Second, a xaml extension which find the value of the key from LocalizationManager.
I wonder if this custom extension could derived from Binding extension, if so, this'll be very easy, just create a Binding Object to the target. If not, I think holding a WEAK reference to the UIElement by xaml extension to dynamic update the text is proper.
This solution is simple but not generic. There're some language read from right to left. It asks the application to show content from right to left.
So, I have another generic solution but more complex.
Instead of xaml extension, we use an attach dependency property.
Do it like this:
<TextBlock LocalizationManager.LocalizationKey="UsernameKey" />
So, the problem now is how to set "Text" property by LocalizationManager?
We use adapters, LocalizationManager will search proper adapter for type "TextBlock"
So, when the application is booting, we register some adapters to LocalizationManager:
LocalizationManager.Current.RegisterAdapter<TextBlock>(new TextBlockAdapter())
This solution is more generic, it supports any kind of control if you provide adapter, but as you see, this solution needs more work and much more complex than the former one.
I hope these design solutions could help you~

WPF - Dynamic tooltip

I have a class ToolTipProvider
which has a method
string GetToolTip(UIElement element)
which will return a specific tooltip for the UIElement specified, based on various factors including properties of the UIElement itself and also looking up into documentation which can be changed dynamically. It will also probably run in a thread so when the form first fires up the tooltips will be something like the visual studio 'Document cache is still being constructed', then populated in the background.
I want to allow this to be used in any wpf form with the minimum effort for the developer. Essentially I want to insert an ObjectDataProvider resource into the Window.Resources to wrap my ToolTipProvider object, then I think I need to create a tooltip (called e.g. MyToolTipProvider) in the resources which references that ObjectDataProvider, then on any element which requires this tooltip functionality it would just be a case of ToolTip="{StaticResource MyToolTipProvider}"
however I can't work out a) how to bind the actual elemnt itself to the MethodParameters of the objectdataprovider, or b) how to force it to call the method each time the tooltip is opened.
Any ideas/pointers on the general pattern I need? Not looking for complete solution, just any ideas from those more experienced
Create a new user control which functions as a tool-tip view factory.
Use your control as the tool-tip, passing any data you need for the factory to your control using binding (e.g. the data, the containing control, ...)
<AnyControl>
<AnyControl.ToolTip>
<YourToolTipControl Content="{Binding}" />
</AnyControl.ToolTip>
</AnyControl>
Not calling myself an expert, but I'd probably attempt such a feature with an attached property. This would be attachable to any element in your UI and you can specify an event handler that gets access to the object to which the property is being attached as well as the value passed to the attached property. You can keep a reference to the element to which your attached property was attached and you would then be able to change the ToolTip whenever you want.

Categories