How to programmatically change binding when datacontext changes - c#

I have a custom control that allows the consumer to send in markup that will be parsed into Inlines, and it will try to match a given Command name with its appropriate ICommand. I have this working except in the case where the DataContext is not set yet. I know that storing the markup and reloading it upon DataContextChanged is not appropriate, but I cannot seem to find anything that works yet. I have tried BindingExpression and Binding to no avail as I do not see a way to attach them to a Hyperlink

I know that storing the markup and reloading it upon DataContextChanged is not appropriate
If you're going to be building a binding to ICommand instances within the DataContext, this is likely the only option that will make sense.
Otherwise, you'd never be able to correct the binding when the data context is changed.

Looking into some other code, I realized that this is all I needed to do:
hyperlink.SetBinding(Hyperlink.CommandProperty, new Binding(description.Command));
The WPF code picks it up generically...I will need to reflect to see exactly what it does, but it works. I could not set the Command property directly, but this worked :)

Related

Unable to bind to DataContext

I am having a really weird problem. I am trying to bind a property to the DataContext but it is not working. This is what I am doing (in the Window.Resources section):
<myNS:MyClass x:Key="myObj" MyProp="{Binding}"/>
Elsewhere in the code, I set the data context like this:
myWindow.DataContext = MyNameSpace.MySingleton.Instance;
I didn't get any errors, but the binding didn't happen. So I added a Debug converter to see if I could figure out what was going on:
<myNS:MyClass x:Key="myObj" MyProp="{Binding Converter={StaticResource Debug}}"/>
I set a breakpoint in the converter and the value being passed was null. Figuring that things were out of order, I set a breakpoint on the line that sets the DataContext. It was hit first, then the breakpoint in the converter. So the DataContext is being set before the binding occurs.
Finally, to try to get something to work, I changed to this:
<myNS:MyClass x:Key="myObj" MyProp="{Binding Source={x:Static myNS:MySingleton.Instance}}"/>
That worked.
I really don't like spreading out the bindings like this. I would rather just bind to the DataContext. The window in question contains many bindings to properties on the DataContext and these all work fine.
Can anyone explain what I am doing wrong here?
JAB
Resources, as well as some other elements like Context Menus are not part of the visual tree.
Thus, they have no governing FrameworkElement to get a data context from. Usually, a standard class won't take advantage of the binding syntax, as it requires deriving from DependencyObject, but if you do end up needing a binding in a resource (say, for a converter) you can use this trick:
Set your root element to have x:Name="Root"
Use your bindings like this:
MyProp="{Binding Source={x:Reference Root}, Path=DataContext.<YourProp>
This binds using the root framework element as the "starting point" and you can get to the data context normally.
What an idiot I am!
I started to respond to #BradleyDotNET (thanks for the response, by the way. It is what helped me solve the problem), and figured out the solution. My class DOES derive from FrameworkElement. I did that because I needed to make use of data binding, even though it has no visible component.
I posted another question dealing with how to instantiate an object declared in the resource section. I would still like to know the answer to that, but since my class derives from FrameworkElement, I don't need to declare it in the resource section; I can put it directly in the tree. This causes it to be instantiated AND inherit the DataContext.

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

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).

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.

Winform: Binding a custom control property to a BindingList

I'm trying to create a binding from my custom control to objects that are in a BindingList.
While with textbox, I can easily write
textBox.DataBindings.Add("Text",myBindingList,"PropertyOfObjectOfBindingList")
With my custom property "Value", this thing doesn't work (the object doesn't get updated).
What should I implement with my custom control to make it works? I already implemented INotifyPropertyChanged, but it doesn't work.
I just want make this line works:
customControl.DataBindings.Add("CustomProperty",myBindingList,"PropertyOfObjectOfBindingList")
EDIT 1:
I read this around web: http://kbalertz.com/327413/control-using-Visual.aspx however is not working for me at the moment, maybe I'm doing something wrong
Since you said your bound object doesn't get updated (I assume from Control -> Object changes), but it is bound correctly, maybe this will help:
customControl.DataBindings.Add("CustomProperty", list, "BoundObjectProperty",
false, DataSourceUpdateMode.OnPropertyChanged);
Maybe the Implementing complex data binding in custom controls article will help.
I solved the problem by myself:
While the article I linked is a good suggestion, there is a wrong part; you don't have to create an event in your custom class with PropertyChangedEventHandler, but just with EventHandler.
public event EventHandler CustomPropertyChanged;
Is enough to make everything works. Obviusly you have to call it when your property changes
EDIT 1:
I discovered a bad thing, while on textboxes, if the control lose focus the bindinglist get updated, on my custom controls this thing happens only when I change selected item in listbox.
I don't find a way to solve this at the moment.

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.

Categories