In a ViewModel I have a property which itself implements INotifyPropertyChanged. When binding to a DependencyProperty I do not get into the DependencyProperty changed callback when I only set properties on the current instance bound to the DependencyProperty even if I raise property changed. (For details, see the code below)
Why do this construction fail?
One way to achieve what I want is to set CurrentFoobar to new instance every time its properties are changed.
Do there exist prettier ways of achieving the wanted behavior?
Edit: I am aware that this particular example may seem irrelevant since one may simply bind proper to the TextBlocks Text property. However I am interested in doing something like this for a control that do not expose proper dependency properties unlike the TextBlock.
Code
I have a ViewModel with a property "CurrentFoobar" of type Foobar.
public class MainViewModel : INotifyPropertyChanged
{
public MainViewModel()
{
var foobar = new Foobar() {Foo = "Hello", Bar = 42};
CurrentFoobar = foobar;
updateCommand = new UpdateCommand(this);
}
private UpdateCommand updateCommand;
public ICommand UpdateCommand
{
get => updateCommand;
}
private Foobar _curfoobar;
public Foobar CurrentFoobar
{
get => _curfoobar;
set
{
_curfoobar = value;
_curfoobar.PropertyChanged += (s, e) => OnPropertyChanged();
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Foobar is a class with two properties string Foo and int Bar. Foobar implements INotifyPropertyChanged.
public class Foobar : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private string _foo;
public string Foo
{
get => _foo;
set
{
_foo = value;
OnPropertyChanged();
}
}
private int _bar;
public int Bar
{
get => _bar;
set
{
_bar = value;
OnPropertyChanged();
}
}
}
In the CurrentFoobar setter I subscribe to PropertyChanged on the current Foobar instance, and raise OnPropertyChanged.
private Foobar _curfoobar;
public Foobar CurrentFoobar
{
get => _curfoobar;
set
{
_curfoobar = value;
_curfoobar.PropertyChanged += (s, e) => OnPropertyChanged();
OnPropertyChanged();
}
}
Furthermore I have a View with a CustomControl that expose a DependencyProperty "FoobarProperty". I bind this DependencyProperty to my ViewModels CurrentFoobar.
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
public static readonly DependencyProperty FoobarProperty = DependencyProperty.Register(
"Foobar", typeof(Foobar), typeof(UserControl1), new PropertyMetadata(default(Foobar), FoobarPropertyChangedCallback));
private static void FoobarPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var uc1 = d as UserControl1;
var newfb = e.NewValue as Foobar;
uc1.TextBlock1.Text = newfb.Foo;
uc1.TextBlock2.Text = newfb.Bar.ToString();
}
public Foobar Foobar
{
get { return (Foobar) GetValue(FoobarProperty); }
set { SetValue(FoobarProperty, value); }
}
}
If I set the CurrentFoobar to a new instance of Foobar the DependencyProperty updates as expected. However if I simply change the properties of the current instance of CurrentFoobar it does not. I would have expected it to update since I raise property changed of CurrentFoobar.
For good measure, here is the UpdateCommand:
public class UpdateCommand : ICommand
{
private MainViewModel _vm;
public UpdateCommand(MainViewModel vm)
{
_vm = vm;
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
_vm.CurrentFoobar.Foo = "World";
_vm.CurrentFoobar.Bar = 84;
}
public event EventHandler CanExecuteChanged;
}
uc1.TextBlock1.Text = newfb.Foo; uc1.TextBlock2.Text = newfb.Bar.ToString();
use bindings in xaml – ASh