Binding to a property by variable name (ideally from xaml) - c#

I'm trying to databind (ideally from XAML as i know how to do this in code behind but it would be far from trivial to traverse my heavily templated tree just for that) to a property who's name i only know at runtime
What i would like to do is not the usual:
Content="{Binding TheProperty}"
But something like
Content="{Binding PropertyName=TheNameIsStoredInThisProperty}"
I'm trying to do this because i generate the UI from templates when binding to my plugins, but the UI is specified in a set of POCO and separate from the ViewModel, so i want to be able to generate my UI and still be able to wire it to the correct properties on the ViewModel, any advice is most welcome.

The immediate solution might be to bind to an arbitrary property in your VM with an IValueConverter that goes both ways, and the ConverterParameter is the string containing the source property name. Once inside the value converter you can use an interception pattern to Reflect out the value you need from the POCO. You can then pass the value up to the source property in the VM. Rather like a pipeline :) This will work but still leaves you with being notified when the POCO changes.
A Markup Extension seems plausible but likely to be brittle and provide naught in the way of performance improvement.
An Attached Behaviour still leaves you with having to Reflect and does not easily solve the problem of notifications originating in the POCO (AFAIK only Unity knows how to do that).

Related

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.

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~

Why ever use a multi binding converter?

Couldn't I just use a single binding converter and as a parameter pass in the DataContext and from there pick what properties I want to use?
If you pass the whole object instead of the individual properties, then the binding expression will not be re-evaluated when the individual properties change. You will be losing the benefit of the INotifyPropertyChanged mechanism.
You might want to be more explicit and take in the minimum extra information (which is just generally good programming practice), or you may want information from more than one source - e.g. Your value might be dependent on a property of the datacontext and the checked state of a checkbox somewhere else in the view.
You can do that, but the binding will not update if the relevant properties change that way. Besides the updates Multibinding is needed for more complex bindings to different controls and data-objects.

Swapping data binding in code

I have two data-bound text boxes. One is bound to a string and the other to a number. The 'default' binding is set in XAML. Under some circumstances I need to reverse the bindings at runtime (the string is usually a prefix but sometimes it's a suffix).
I have the following code in my view model, called when the window is loaded:
Binding stringBinding = BindingOperations.GetBinding(view.seqLeft, TextBox.TextProperty);
Binding numberBinding = BindingOperations.GetBinding(view.seqRight, TextBox.TextProperty);
view.seqLeft.SetBinding(TextBlock.TextProperty, numberBinding);
view.seqRight.SetBinding(TextBlock.TextProperty, stringBinding);
After that the code loads the properties to which the binding refers.
The problem is that the 'new' binding doesn't seem to work. What have I missed? Is there a better way?
I might consider exposing Prefix and Suffix strings to which View can bind, then use logic within the ViewModel, or whatever backing object you're using, to fill those strings accordingly. This option neatly segments the business concern from the visual and simplifies what you have to keep track of in your view.
Why monkey around with the bindings at all? If you want to have a TextBox that's bound to one of two different things, create two TextBoxes, put them in the same location, and toggle their visibility based on whatever your swap condition is.
The only thing wrong with my code was the TextBlock.TextProperty in the SetBinding calls! They should, of course, have been TextBox.TextProperty but I'd messed with it so long I wasn't seeing the wood for the trees.

ValueConverter with data binding

Is it possible to add a dependency property to a ValueConverter and bind it to a property of the object to which the converter is applied?
It isn't possible to do this in XAML. What you'd usually want to use for the sort of problem I'm guessing you have is a IMultiValueConverter.
If you really had to you could wire it up like you suggest in the code behind for your view but I really wouldn't recommend it. First it is much more difficult to manage and second your property won't be updated when the value you've bound to the new dependency property changes (i.e. the Convert method won't be called again). You're much better off using an IMultiValueConverter.

Categories