WPF中PropertyChanged UpdataSourceTrigger的奇怪行为



我有一个这样的实体:

public class Person
{
    public string Name { get; set; }
    public Person()
    {
        Name = "Godspeed";
    }
}

在XAML中有三个文本框和一个按钮:

<Window x:Class="WpfApplication19.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication19"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <local:Person />
    </Window.DataContext>
    <StackPanel>
        <TextBox Text="{Binding Name,UpdateSourceTrigger=PropertyChanged}" />
        <TextBox Text="{Binding Name,UpdateSourceTrigger=PropertyChanged}" />
        <TextBox Text="{Binding Name,UpdateSourceTrigger=PropertyChanged}" />
        <Button Click="Button_Click">Click</Button>
    </StackPanel>
</Window>

奇怪的是,实体"Person"没有实现INotifyPropertyChanged,但是当一个文本框被改变时,它会修改源(Person对象),但是我们没有引发property changed事件,但其余两个文本框会自动改变。

当按钮被点击时,我们直接更新源代码,代码如下:

((Person)DataContext).Name = "Godspeed";

它不更新。我认为的是,如果Person类实现了INotifyPropertyChanged,这个行为是正常的,但现在这个类不实现接口,但它也更新接口。如果你有线索,请告诉我原因。谢谢。

原因是PropertyDescriptor,参见下面的线程,同样的问题也出现了:数据绑定系统如何知道属性何时被更改?

以下是其中两个答案

我认为魔法在于绑定系统的使用PropertyDescriptor (SetValue)可能会引发一个valuechange属性描述符可能是共享的,而事件是在每个对象)。


我不在微软,但我可以证实这一点。如果PropertyDescriptor是用于更新值,然后进行相关更改通知会自动传播。

编辑
您可以通过命名Person DataContext对象

来验证这一点
<Window.DataContext>
    <local:Person x:Name="person"/>
</Window.DataContext>

,并将以下代码添加到MainWindow

public MainWindow()
{
    InitializeComponent();
    PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(person);
    PropertyDescriptor nameProperty = properties[0];
    nameProperty.AddValueChanged(person, OnPropertyChanged);
}
void OnPropertyChanged(object sender, EventArgs e)
{
    MessageBox.Show("Name Changed");
}

一旦你改变了三个文本框中的任何一个的值,你将结束在事件处理程序OnPropertyChanged.

就像你说的,你只需要实现INotifyPropertyChanged

当您从代码设置属性并需要将此更改反映到您的UI时使用PropertyChanged事件(UI将捕获PropertyChanged事件,并且由于您的UpdateSourceTrigger, UI将被更新)。另一边(从UI改变)不需要任何PropertyChanged,这就是为什么你得到这个行为

就像这样试试:

    public class Person : INotifyPropertyChanged
    {
            #region INotifyPropertyChanged Members
            /// <summary>
            /// Property Changed Event
            /// </summary>
            public event PropertyChangedEventHandler PropertyChanged;
            /// <summary>
            /// Property Changed
            /// </summary>
            /// <param name="propertyName"></param>
            protected void OnPropertyChanged(string propertyName)
            {
                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
            #endregion
    private string name;
    public string Name
    {
      get { return name; }
      set 
      {
        name = value;
        OnPropertyChanged("Name");
      }
    }
}

使用这段代码,当您设置Name时,PropertyChanged事件将被触发,因此将相应地更新UI:)

它不仅适用于updatesourcetrigger=propertychanged,而且适用于默认值(失去焦点)。除了@Meleak所说的,我想指出这是一种良好的行为。ui所做的任何更改都会传播到所有绑定目标。绑定引擎希望一次将此更改传播到所有控件。如果您通过代码进行更改,而不实现INotifyPropertyChanged -从代码中所做的更改根本不会反映出来。同样,对于具有相同绑定源的所有控件。所有控件都以同步的方式工作。

相关内容

  • 没有找到相关文章

最新更新