简体   繁体   English

当绑定到引用保持不变的对象时,忽略PropertyChanged

[英]PropertyChanged is ignored when Binding to object where reference stays the same

I'm pretty new to the WPF/Binding world, but now I'm using it for some time with some degrees of success. 我对WPF / Binding领域还很陌生,但是现在我使用它已有一段时间,并且取得了一定程度的成功。

Now I'm stuck with a problem very similar to the one described in this question , but regarding a class instead of an IEnumerable. 现在,我遇到了一个非常类似于该问题中所述问题的问题 ,只是问题涉及的是类而不是IEnumerable。 I'm not sure if the behavior is intentional also for a class or if there is a way to solve it. 我不确定该行为是否也是针对某个班级的故意行为或是否有解决方法。

Let's say I have my simple custom class "Vector3" that contains 3 doubles Vector3.cs 假设我有一个简单的自定义类“ Vector3”,其中包含3个Doubles Vector3.cs

    public class Vector3
    {
        public double X { get; set; }
        public double Y { get; set; }
        public double Z { get; set; }

        public Vector3(double x, double y, double z)
        {
            X = x;
            Y = y;
            Z = z;
        }

        public Vector3(Vector3 vec)
        {
            X = vec.X;
            Y = vec.Y;
            Z = vec.Z;
        }

        public override bool Equals(object obj)
        {
            if (!(obj is Vector3))
                return false;

            Vector3 other = obj as Vector3;

            return X == other.X && Y == other.Y && Z == other.Z;
        }

        public override int GetHashCode()
        {
            unchecked
            {
                return (X.GetHashCode() * 42) ^ Y.GetHashCode() + Z.GetHashCode();
            }
        }
    }

And I have a user-control that exposes a DependencyProperty of this type 我有一个用户控件,它公开了这种类型的DependencyProperty

ucVector3.xaml.cs ucVector3.xaml.cs

public partial class ucVector3 : UserControl
    {
        public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value",
                     typeof(Vector3), typeof(ucVector3),
                     new FrameworkPropertyMetadata(null, new PropertyChangedCallback(_OnModelChanged)));

        private static void _OnModelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Console.WriteLine("Binding worked! I've received a new Vector3 " +
                              "with value X = " + (e.NewValue as Vector3).X); 
        }

        public Vector3 Value
        {
            get
            {
                return (Vector3)GetValue(ValueProperty);
            }
            set
            {
                SetValue(ValueProperty, value);
            }
        }
    ...

Then I try to use this user-control binding the Value property like in this example: 然后,我尝试使用此用户控件绑定Value属性,如以下示例所示:

MainWindow.xaml MainWindow.xaml

<Window x:Class="StackOverflow.Example.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:StackOverflow.Example"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid Background="Azure">
        <Grid.RowDefinitions>
            <RowDefinition Height="5*"/>
            <RowDefinition Height="1*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Button Content="Update" Margin="5" Grid.Row="1" Grid.ColumnSpan="2" Click="Button_Click" />
        <local:ucVector3 Value="{Binding SameReference}" Margin="5" />
        <local:ucVector3 Value="{Binding NewReference}" Margin="5" Grid.Column="1" />
    </Grid>
</Window>

MainWindow.xaml.cs MainWindow.xaml.cs

    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        #region INotifyPropertyChanged
        SynchronizationContext uiContext = SynchronizationContext.Current;
        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            if (uiContext != SynchronizationContext.Current)
            {
                uiContext.Send(_ =>
                {
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
                }, null);
            }
            else
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion

        private Vector3 newValue = new Vector3(0, 0, 0);

        public Vector3 SameReference { get; set; }
        public Vector3 NewReference { get; set; }

        public MainWindow()
        {
            this.DataContext = this;
            InitializeComponent();

        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            newValue.X = newValue.X + 2;
            newValue.Y = newValue.Y + 3;
            newValue.Z = newValue.Z + 4;

            SameReference = newValue;
            NewReference = new Vector3(newValue);

            OnPropertyChanged("SameReference"); //successful notify, ignored values
            OnPropertyChanged("NewReference"); //successful notify, processed values
        }
    }

Pressing the button the first time both user-controls will be updated with (3,4,5), but from the second time, only the "NewReference" property will be updated in the right user-control. 第一次按下该按钮,两个用户控件都将被更新为(3,4,5),但是从第二次开始,将仅在正确的用户控件中更新“ NewReference”属性。

I get that for IEnumerables WPF will propagate the OnPropertyChanged event only if the reference is different, and changes in the IEnumerable need to call the INotifyCollectionChanged event instead. 我了解到,对于IEnumerables,WPF仅在引用不同的情况下才会传播OnPropertyChanged事件,并且IEnumerable中的更改需要改为调用INotifyCollectionChanged事件。

Why my "OnPropertyChanged("SameReference")" is not propagated? 为什么我的“ OnPropertyChanged(“ SameReference”)”没有传播? I changed the values, I want the event to propagate to update the interface, or I wouldn't call the event... 我更改了值,希望事件传播以更新接口,否则我不会调用该事件...

Is this behavior intentional? 这种行为是故意的吗? Why it checks the object reference and not maybe if it is Equals? 为什么要检查对象引用,而不是检查是否等于? Is there a way to "force" the event to go through? 有办法“强迫”事件进行吗? Or how should I organize my classes in this case? 还是在这种情况下应该如何组织课程?

Here you can download the example solution described in this question , created in VisualStudio2015. 在这里,您可以下载在VisualStudio2015中创建的此问题中描述的示例解决方案

Thanks to all for your time. 感谢您的时间。

from i have seen in your project, you have to comment these lines in your ucVector3.xaml.cs, these lines avoid to update your usercontrol: 从我在您的项目中看到的来看,您必须在ucVector3.xaml.cs中注释以下行,这些行避免更新用户控件:

        if (value.X == lastNudValue.X && value.Y == lastNudValue.Y && value.Z == lastNudValue.Z)
           return;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM