PropertyChanged игнорируется, когда привязка к объекту, где ссылка остается прежней - PullRequest
0 голосов
/ 11 апреля 2019

Я довольно новичок в мире WPF / Binding, но теперь я использую его в течение некоторого времени с некоторой степенью успеха.

Теперь я застрял с проблемой, очень похожей на однуописанный в этот вопрос , но относительно класса вместо IEnumerable.Я не уверен, является ли поведение преднамеренным также для класса или если есть способ его решить.

Допустим, у меня есть свой простой пользовательский класс "Vector3", который содержит 3 двойника 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();
            }
        }
    }

И у меня есть пользовательский элемент управления, который предоставляет свойство DependencyProperty этого типа

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

Затем я пытаюсь использовать этот пользовательский элемент управленияпривязка свойства Value, как в этом примере:

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

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

При первом нажатии кнопки оба пользователяэлементы управления будут обновлены с помощью (3,4,5), но со второго раза будет обновлено только свойство «NewReference» в правом пользовательском элементе управления.

Я получаю, что для IEnumerables WPF будет распространятьСобытие OnPropertyChanged, только если ссылка отличается, и изменения в IEnumerable должны вызывать событие INotifyCollectionChanged.

Почему мой "OnPropertyChanged (" SameReference ")" "не распространяется?Я изменил значения, хочу, чтобы событие распространялось, чтобы обновить интерфейс, или я не назвал бы событие ...

Это поведение является преднамеренным?Почему он проверяет ссылку на объект, а не может быть, если он равен?Есть ли способ «заставить» событие пройти?Или как мне организовать свои занятия в этом случае?

Здесь вы можете скачать пример решения, описанного в этом вопросе , созданный в VisualStudio2015.

Спасибо всем за вашевремя.

1 Ответ

0 голосов
/ 12 апреля 2019

Из того, что я видел в вашем проекте, вы должны прокомментировать эти строки в вашем ucVector3.xaml.cs, эти строки избегают обновления вашего usercontrol:

        if (value.X == lastNudValue.X && value.Y == lastNudValue.Y && value.Z == lastNudValue.Z)
           return;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...