WPF binding fails with custom add and remove accessors for INotifyPropertyChanged.PropertyChanged
- by emddudley
I have a scenario which is causing strange behavior with WPF data binding and INotifyPropertyChanged. I want a private member of the data binding source to handle the INotifyPropertyChanged.PropertyChanged event.
I get some exceptions which haven't helped me debug, even when I have "Enable .NET Framework source stepping" checked in Visual Studio's options:
A first chance exception of type 'System.ArgumentException' occurred in mscorlib.dll
A first chance exception of type 'System.ArgumentException' occurred in mscorlib.dll
A first chance exception of type 'System.InvalidOperationException' occurred in PresentationCore.dll
Here's the source code:
XAML
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="TestApplication.MainWindow"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
Height="100" Width="100">
<StackPanel>
<CheckBox IsChecked="{Binding Path=CheckboxIsChecked}" Content="A" />
<CheckBox IsChecked="{Binding Path=CheckboxIsChecked}" Content="B" />
</StackPanel>
</Window>
Normal implementation works
public partial class MainWindow : Window, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public bool CheckboxIsChecked
{
get { return this.mCheckboxIsChecked; }
set
{
this.mCheckboxIsChecked = value;
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs("CheckboxIsChecked"));
}
}
private bool mCheckboxIsChecked = false;
public MainWindow() { InitializeComponent(); }
}
Desired implementation doesn't work
public partial class MainWindow : Window, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged
{
add { lock (this.mHandler) { this.mHandler.PropertyChanged += value; } }
remove { lock (this.mHandler) { this.mHandler.PropertyChanged -= value; } }
}
public bool CheckboxIsChecked
{
get { return this.mHandler.CheckboxIsChecked; }
set { this.mHandler.CheckboxIsChecked = value; }
}
private HandlesPropertyChangeEvents mHandler = new HandlesPropertyChangeEvents();
public MainWindow() { InitializeComponent(); }
public class HandlesPropertyChangeEvents : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public bool CheckboxIsChecked
{
get { return this.mCheckboxIsChecked; }
set
{
this.mCheckboxIsChecked = value;
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs("CheckboxIsChecked"));
}
}
private bool mCheckboxIsChecked = false;
}
}