In my ViewModel, I have a class "A" with a child property "B" that is also a custom class. Both classes implement INotifyPropertyChanged and B's PropertyChanged event is hooked up to fire A's PropertyChanged event (with the correct property name of "B").
I also have a DependencyProperty "DPB" on my ViewModel that is bound to B in code with a very simple binding (new Binding("A.B")).
Now I have three TextBoxes in my view:
On first run, both A.B and the DPB textboxes show the correct value. But when I change the A.B.C textbox, only the A.B textBox is updated - the DPB textBox is not updated.
I have debugged through all of the PropertyChanged notifying code and they are all hit with the correct values passed.
The problem seems to be that the DependencyProperty (or it's binding) is not being updated when the PropertyChanged event is fired. Can anyone tell me why or how to change this behaviour?
thank you.
I have bad news for you.
Inside DependencyObject.SetValue
the check is located, which verify if new value equals to old value. So if you are binded to A.B
, and changing of A.B.C
produces PropertyChanged event for A.B
, Binding
mechanizm will handle this event and even call DependencyObject.SetValue
. But then (due to equality of old and new A.B
values) no changes will be applied to DP.
In order to achieve correct DP fireing, you should create new instance of A.B, that concludes in great headache.
UPDATED
You could use Freezable object, which supports notification that it has changed when its property is changed. DependencyObject works with Freezables correctly, so next example does what you need.
Model classes:
public class A
{
public A()
{
this.B = new B();
}
public B B
{
get; private set;
}
}
public class B : Freezable, INotifyPropertyChanged
{
protected override Freezable CreateInstanceCore()
{
return new B();
}
private string _c = "initial string";
public string C
{
get
{
return _c;
}
set
{
this._c = value;
this.OnPropertyChanged("C");
this.OnChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
var safe = this.PropertyChanged;
if (safe != null)
{
safe(this, new PropertyChangedEventArgs(name));
}
}
}
Xaml:
<StackPanel>
<TextBox Text="{Binding A.B.C}" />
<TextBox Text="{Binding MyProperty.C}" />
<Button Click="Button_Click"/>
</StackPanel>
Code behind:
public partial class TextBoxesView : UserControl
{
public TextBoxesView()
{
InitializeComponent();
this.A = new A();
this.DataContext = this;
BindingOperations.SetBinding(this, TextBoxesView.MyPropertyProperty, new Binding("A.B"));
}
private void Button_Click(object sender, RoutedEventArgs e)
{
this.A.B.C = DateTime.Now.ToString();
}
public A A
{
get;
private set;
}
public B MyProperty
{
get
{
return (B)this.GetValue(TextBoxesView.MyPropertyProperty);
}
set
{
this.SetValue(TextBoxesView.MyPropertyProperty, value);
}
}
public static readonly DependencyProperty MyPropertyProperty =
DependencyProperty.Register("MyProperty",
typeof(B),
typeof(TextBoxesView),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.None, (d, e) => { }));
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With