Сбой связывания WPF с пользовательскими средствами добавления и удаления для INotifyPropertyChanged.PropertyChanged - PullRequest
1 голос
/ 01 июня 2010

У меня есть сценарий, который вызывает странное поведение с привязкой данных WPF и INotifyPropertyChanged. Я хочу, чтобы закрытый член источника привязки данных обрабатывал событие INotifyPropertyChanged.PropertyChanged.

Вот исходный код:

1007 * 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> Нормальная реализация работает

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(); }
}

Желаемая реализация не работает

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;
    }
}

Ответы [ 2 ]

4 голосов
/ 01 июня 2010

Это всего лишь предположение, но я думаю, что это может быть связано с тем, что параметр sender, передаваемый обработчику событий, является экземпляром HandlesPropertyChangeEvents, когда привязка ожидает экземпляр MainWindow.

Попробуйте изменить код так, чтобы отправителем был экземпляр MainWindow:

private PropertyChangedEventHandler _propertyChanged;
public event PropertyChangedEventHandler PropertyChanged
{
    add { lock (this.mHandler) { this._propertyChanged += value; } }
    remove { lock (this.mHandler) { this._propertyChanged -= value; } }
}


...

public MainWindow()
{
    InitializeComponent();
    mHandler.PropertyChanged += mHandler_PropertyChanged;
}

private void mHandler_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
    var handler = _propertyChanged;
    if (handler != null)
        _propertyChanged(this, e);
}
2 голосов
/ 01 июня 2010

Мое рабочее решение почти точно такое же, как «желаемая реализация» в моем вопросе, с добавлением свойства Sender.

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();
        this.mHandler.Sender = this;
    }

    public class HandlesPropertyChangeEvents : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public Sender { get; set; }

        public bool CheckboxIsChecked
        {
            get { return this.mCheckboxIsChecked; }
            set
            {
                this.mCheckboxIsChecked = value;
                PropertyChangedEventHandler handler = this.PropertyChanged;
                if (handler != null)
                    handler(this.Sender, new PropertyChangedEventArgs("CheckboxIsChecked"));
            }
        }

        private bool mCheckboxIsChecked = false;
    }
}

Этот пример немного искусственный, но в моем приложении перемещение кода обработки событий за пределы связанного класса имеет смысл.

...