WPF 绑定因 INotifyPropertyChanged.PropertyChanged 的​​自定义添加和删除访问器而失败

发布于 2024-09-03 22:41:19 字数 2568 浏览 5 评论 0原文

我有一个场景导致 WPF 数据绑定和 INotifyPropertyChanged 出现奇怪的行为。我想要数据绑定源的私有成员来处理 INotifyPropertyChanged.PropertyChanged 事件。

这是源代码:

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

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.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

赴月观长安 2024-09-10 22:41:20

我的工作解决方案几乎与我的问题中的“所需实现”完全相同,只是添加了 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;
    }
}

这个示例有点人为,但在我的应用程序中,将事件处理代码移到绑定类之外是有意义的。

My working solution is almost exactly the same as the "desired implementation" in my question, with the addition of the Sender property.

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

This example is a bit artificial, but in my application moving the event handling code outside of the bound class makes sense.

弥枳 2024-09-10 22:41:19

这只是一个猜测,但我认为这可能是因为传递给事件处理程序的 sender 参数是 HandlesPropertyChangeEvents 的实例,而绑定需要 的实例主窗口

尝试更改您的代码,以便发送者是 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);
}

That's just a guess, but I think it might be because the sender parameter passed to the event handler is an instance of HandlesPropertyChangeEvents, when the binding expects an instance of MainWindow.

Try to change your code so that the sender is the MainWindow instance :

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);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文