WPF data binding with delimited path, not updating target - wpf

I have a custom WPF usercontrol which has a dependency property (snippet below). Which is not firing it's PropertyChangedCallback correctly.
CustomControl:
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register(
"Value", typeof(float?), typeof(CustomControl),
new UIPropertyMetadata(new PropertyChangedCallback(OnDependencyPropertyChanged)));
public float? Value
{
get { return (float?)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
private static void OnDependencyPropertyChanged(object sender, DependencyPropertyChangedEventArgs e)
{
// Do something
}
When I bind to the property with a simple path, all is fine. However when I use the delimited path syntax, the dependency property is not updated when it should be.
Working binding:
<namespace:CustomControl Value={Binding ViewModelProperty}/>
Not working binding:
<namespace:CustomControl Value={Binding ViewModelProperty.ObjectProperty}/>
With the working syntax, the OnDependencyPropertyChanged event handler is called in response to PropertyChanged events for ViewModelProperty fired by the view model. However with the 2nd syntax the OnDependencyPropertyChanged event handler is only called for changes to ObjectProperty, and is not called for changes to ViewModelProperty. Do I need to do any additional setup to make the delimited (.) path syntax work appropriately? (Have the same behavior that properties like TextBox.Text have by default)

Have you tried your binding with the Path attribute?
<nmspc:CustomControl Value="{Binding Path=ViewModelProperty.ObjectProperty}" />
I recall that when building a two-way binding programatically the Path attribute is required.

Related

WPF - What's the interest of dependency property without callback

I don't understand the interest of a dependency property without callback defined.
A callback is just an added convenience -- dependency properties are integrated into the framework runtime, and have a built-in callback mechanism that updates any bindings. That is, if you set a binding with a dependency property as the source, then the target will update automatically when the dependency property changes.
For example, let's say you have a custom control with a DP defined:
public string SomeDP
{
get { return (string)GetValue(SomeDPProperty); }
set { SetValue(SomeDPProperty, value); }
}
public static readonly DependencyProperty SomeDPProperty =
DependencyProperty.Register("SomeDP", typeof(string), typeof(SomeFrameworkElement), new PropertyMetadata(null));
And if you set up a binding with the DP as the source for a TextBlock's "Text" property:
<local:SomeFrameworkElement x:Name="someFrameworkElement" SomeDP="initial" />
<TextBlock Text="{Binding ElementName=someFrameworkElement,Path=SomeDP}" />
Then whenever "someFrameworkElement"'s "SomeDP" property changes, the text will also change.

Binding in Code doesn't react to source object changing

I have a dependency property on a class inheriting from adorner, like so:
public class LoadingAdorner : Adorner
{
public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof (string), typeof (LoadingAdorner), new PropertyMetadata(default(string)));
public string Text
{
get { return (string) GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public static readonly DependencyProperty IsShowingProperty = DependencyProperty.Register("IsShowing", typeof (bool), typeof (LoadingAdorner), new PropertyMetadata(default(bool)));
...
}
Adorner's don't really have any XAML, but I wanted the text of this adorner to be bindable to the viewmodel. So I create the binding in code, in the view's constructor, like so:
private readonly LoadingAdorner _loading;
public MainWindow()
{
InitializeComponent();
_loading = new LoadingAdorner(MainPage);
var bind = new Binding("LoadingText"){Source = DataContext};
_loading.SetBinding(LoadingAdorner.TextProperty, bind);
}
The DataContext is my view model, my view model implements INotifyPropertyChanged, LoadingText is a string property that calls OnPropertyChanged, etc. All bindings in XAML work fine, however, the code binding does not.
I believe it is because at the time of creating the binding, the view model has not yet been set to the DataContext (it is null), I do this on the line after creating the view. If I set this binding to a property on my view using Source = this, it works.
My question is, why are the XAML bindings are capable of reacting to the source object changing, while the code binding doesn't appear to be? Is there a proper way for me to create a binding that will react to this similiar to the XAML bindings?
Binding do not and cannot react to source changes, it is a logical impossibility, objects do not change properties and references to objects change. Bindings can react to DataContext property changes but only if you do not do something horrible like Source = DataContext which kills the mechanism by getting the current data context once only. Just drop that so the DataContext is the default source again and the binding should react to the changes.
If the DataContext is on another object than the one that is bound it needs to be moved into the Path, i.e. new Binding("DataContext.LoadingText"){ Source = this }.

Why does my UI not update to reflect the data I have bound to it?

I've bound the visibility of some buttons to a bool, but when the bool changes, the button's visibility does not change. Why could this be?
The boolean is set up as such:
public static readonly DependencyProperty editModeToggle = DependencyProperty.Register("editMode", typeof(bool), typeof(Window));
public bool EditMode
{
get { return(bool)GetValue(editModeToggle); }
set { SetValue(editModeToggle, value); }
}
I'm pretty sure the binding isn't at fault.
[Note: I have set up a Converter that works and the binding works. The visibility just doesn't change when I change from true to false or vice versa]
Binding:
<Button Content="Test" Visibility="{Binding ElementName=mainWindow, Path=EditMode, Converter={StaticResource BooltoVisibilityConverter}/>
There are a few things you need to check when a binding does not work as expected:
Does the bool property notify change using
INotifyPropertyChanged?
Do you use a converter to convert from
bool to Visibility?
Do you see any binding errors in output
window?
Have you tried putting a breakpoint on binding in xaml
or setter in bool property?
As you have mentioned in your comment, you have not implemented INotifyPropertyChanged interface.
The need to implement the interface is whenever value of the property in ViewModel changes, there has be be a way for binding to know that. So, after implementing INotifyPropertyChanged, for each property, you raise the PropertyChanged event with the property name in it. That way, the binding knows that value of the property has changed.
There are lots of articles online. Here is one to get you started: INotifyPropertyChanged and WPF
Dependency Property registration is not correct -
public static readonly DependencyProperty editModeToggle =
DependencyProperty.Register("editMode", typeof(bool), typeof(Window));
It should be-
public static readonly DependencyProperty editModeToggle =
DependencyProperty.Register("EditMode", typeof(bool), typeof(Window));
Notice the spelling of property - 'E' should be capital since its case sensitive and your property name is EditMode not editMode.
In this case you don't need point 1 from decyclone list since you are using a dependency property. I think that you should add Mode=TwoWay in binding if you don't have it, that will solve it.

Silverlight data binding to parent user control's properties with using MVVM in both controls

I have two UserControls ("UserControlParentView" and "UserControlChildView") with MVVM pattern implemented in both controls. Parent control is a container for Child control and child control's property should be updated by data binding from Parent control in order to show/hide some check box inside Child control.
Parent Control Description
UserControlParentViewModel has property:
private bool isShowCheckbox = false;
public bool IsShowCheckbox
{
get { return isShowCheckbox; }
set { isShowCheckbox = value; NotifyPropertyChanged("IsShowCheckbox"); }
}
UserControlParentViewModel - how I set DataContext of Parent control:
public UserControlParentView()
{
InitializeComponent();
this.DataContext = new UserControlParentViewModel();
}
UserControlParentView contains toggle button (in XAML), bound to UserControlParentViewModel's property IsShowCheckbox
<ToggleButton Grid.Column="1" IsChecked="{Binding IsShowCheckbox, Mode=TwoWay}"></ToggleButton>
Also Parent control contains instance of child element (somewhere in XAML)
<local:UserControlChildView IsCheckBoxVisible="{Binding IsShowCheckbox}" ></local:UserControlChildView>
so property in child control should be updated when user togggle/untoggle button.
Child control contains Boolean property to be updated from parent control, but nothing happened! Breakpoint never fired!
Property in UserControlChildView that should be updated from Parent control (here I plan to make chechBox visible/hidden in code behind):
public bool IsCheckBoxVisible
{
get { return (bool)GetValue(IsCheckBoxVisibleProperty); }
set { SetValue(IsCheckBoxVisibleProperty, value); }
}
// Using a DependencyProperty as the backing store for IsCheckBoxVisible. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsCheckBoxVisibleProperty =
DependencyProperty.Register("IsCheckBoxVisible", typeof(bool), typeof(TopMenuButton), new PropertyMetadata(false));
So the question is - what I'm doing wrong? Why child's property is never updated? BTW - there is no any binding error warnings in Output window...
You don't state where you put the breakpoint "never fired!". My guess is you placing a break point in the set mutator method of the IsCheckBoxVisible property.
You are operating under the assumption that the binding on that property will at some point cause the set method to be called when assigning the value. However the Silverlight binding framework actuall calls SetValue directly. It passes to the SetValue method the value of IsCheckBoxVisibleProperty and the value to be assigned.
I can't see all your code, so I can't work out everything, but a couple of questions:
In your DependencyProperty.Register call, you specify typeof(TopMenuButton), which should be the UserControlChildView - I don't know if that is your view or not?
You don't set up a callback method for property changed. To do this you would have to define the properties for the FrameworkPropertyMetadata, before registering the depencencyProperty like so:
FrameworkPropertyMetadata metadata = new FrameworkPropertyMetadata();
metadata.PropertyChangedCallback += OnSpacePropertyChanged;
You'd then have to declare OnSpacePropertyChanged, but you can at least respond to setting the property from there.
I am pretty sure you can't bind to a dependency property on a user control in Silverlight 3. I've tried it myself 9 months ago, and attempted all sorts of things to get it to work. Eventually I read somewhere that it simply wasn't possible. I have done it in WPF, so was beating my head on it for a while, thinking it was my implementation.
So, on the surface your code looks correct but this won't help.
I thought it was slated as something to be fixed in SL4.
Are you using SL4?
Hoho!! I've got it to work!
In child control I've changed property a bit
public bool IsCheckBoxVisible
{
get { return (bool)GetValue(IsCheckBoxVisibleProperty); }
set { SetValue(IsCheckBoxVisibleProperty, value); }
}
// Using a DependencyProperty as the backing store for IsCheckBoxVisible. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsCheckBoxVisibleProperty =
DependencyProperty.Register("IsCheckBoxVisible", typeof(bool), typeof(UserControlChildView), new PropertyMetadata(false, new PropertyChangedCallback((d, dc) =>
{
var button = d as UserControlChildView;
button.CheckBoxVisibility = ((bool)dc.NewValue) ? Visibility.Visible : Visibility.Collapsed;
})));
so now I have new event subscription (see anonymous method) and it fires when in parent control IsShowCheckbox property is changed!
CheckBoxVisibility depend.property looks like this:
public Visibility CheckBoxVisibility
{
get { return (Visibility)GetValue(CheckBoxVisibilityProperty); }
set { SetValue(CheckBoxVisibilityProperty, value); }
}
// Using a DependencyProperty as the backing store for IsCheckBoxVisible. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CheckBoxVisibilityProperty =
DependencyProperty.Register("CheckBoxVisibility", typeof(Visibility), typeof(UserControlChildView), new PropertyMetadata(Visibility.Collapsed));
Constructor of serControlChildView looks like:
public UserControlChildView()
{
InitializeComponent();
this.LayoutRoot.DataContext = this;
}
So seems like it works! Thank you for your help, folks!
Ok, it seems like everything worked fine and I was confused just by non-fired breakpoint.
For simplicity I've decided to remove IsCheckBoxVisible boolean depend.property from the Child control and to bind checkBox visibility in Child control directly to CheckBoxVisibility depend.property (type is Visibility).
Also in the Parent control now I have this:
<local:UserControlChildView CheckBoxVisibility="{Binding Path=CheckboxControlVisibility}"></local:UserControlChildView>
So in the Parent control now I have CheckboxControlVisibility property (type is Visibility)

wpf how to tell when databinding has finished?

I've got a custom control which has a DependencyProperty MyAnimal - I'm binding an Animal Property on my ViewModel to the MyAnimal DependencyProperty.
I've stuck a TextBox on the Control so I can trigger an Event - whenever I trigger the event the MyAnimal property has been set - however if I put a break point on the Setter of the MyAnimal property it never gets fired!
I guess I'm missing something fundamental about WPF Dependency Properties/Binding?!
And so my question is, if I can't use the Setter how can I find out when its been set? If I put if I put a break point after InitializeComponent() its null and I had a look to see if theres an Event a can hook up to - DatabindingFinished or similar? but can't see what it would be ...
Can anyone assist please?
Thanks,
Andy
public partial class ControlStrip
{
public ControlStrip()
{
InitializeComponent();
}
public Animal MyAnimal
{
get
{
return (Animal)GetValue(MyAnimalProperty);
}
set
{
SetValue(MyAnimalProperty, value);
}
}
public static readonly DependencyProperty MyAnimalProperty =
DependencyProperty.RegisterAttached("MyAnimal", typeof (Animal), typeof (ControlStrip));
private void TextBox_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
{
var myAnimal = MyAnimal;
MessageBox.Show(myAnimal.Name);
}
}
The setter methods are never called by the runtime. They go directly to the DependencyProperty. You will need to add an additional argument to your call to RegisterAttached(). There you can add a PropertyChangedCallback.
Here is some sample code:
public static readonly DependencyProperty MyAnimalProperty =
DependencyProperty.RegisterAttached("MyAnimal", typeof (Animal), typeof (ControlStrip), new PropertyMetadata(AnimalChanged));
private static void AnimalChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
// Do work here
}
The setter is only there for your use - you actually can leave the property off entirely, since DataBinding uses the actual DependencyProperty itself, not the CLR property.
If you need to see when the property changes, you will need to specify PropertyMetadata on your dependency property, and provide a PropertyChangedCallback.
For details, I recommend reading Dependency Property Metadata.

Resources