I almost feel embarrassed to ask this, but after three hours, I have run out of ideas and patience.
Situation:
A ViewModel with properly implemented INotifyPropertyChanged with one string property.
public class ViewModel : INotifyPropertyChanged { #region INotifyPropertyChanged Members public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } #endregion private string _Header; public string Header { get { return _Header; } set { _Header = value; OnPropertyChanged(); } } public static ViewModel Current { get; private set; } public ViewModel() { Current = this; } }
A MainWindow.xaml
<Window x:Class="CollectionEditor.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:CollectionEditor" mc:Ignorable="d" Title="MainWindow" Height="350" Width="525"><Window.Resources><local:ViewModel x:Key="ViewModel" /></Window.Resources><StackPanel DataContext="{StaticResource ViewModel}"><!--the textblock here properly updates:--><TextBlock Text="{Binding Header}" /><local:MyUserControl Header="{Binding Header, Mode=TwoWay}" /><Button Content="add" VerticalAlignment="Bottom" Click="Button_Click" /></StackPanel></Window>
With
private void Button_Click(object sender, RoutedEventArgs e) { string now = DateTime.Now.ToString(); ViewModel.Current.Header = now; }
And finally a UserControl that exposes the "Header" dependency property:
<UserControl x:Class="CollectionEditor.MyUserControl" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:CollectionEditor" mc:Ignorable="d"x:Name="self" DataContext="{Binding ElementName=self}" d:DesignHeight="300" d:DesignWidth="300"><StackPanel><TextBlock Text="{Binding Header}" /></StackPanel></UserControl>
public partial class MyUserControl : UserControl, INotifyPropertyChanged { #region INotifyPropertyChanged Members public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } #endregionpublic string Header { get { return (string)GetValue(HeaderProperty); } set { //This setter is never invoked?! Debugger.Break(); SetValue(HeaderProperty, value); OnPropertyChanged(); } } public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register(nameof(Header), typeof(string), typeof(MyUserControl), new PropertyMetadata(null)); public MyUserControl() { InitializeComponent(); } }
The INotifyPropertyChanged implementation works, because the TextBlock in the main window does update when the button is clicked.
But something is wrong with the dependency property, because the setter is never invoked and the UserControl's text block does not update.
I can't figure out what's wrong, especially because the exact same design works in UWP just fine.
What am I missing here??
thanks
Michael