【问题标题】:A weird behavior of PropertyChanged UpdataSourceTrigger in WPFWPF 中 PropertyChanged UpdataSourceTrigger 的奇怪行为
【发布时间】:2011-10-25 14:43:47
【问题描述】:

我有一个这样的实体:

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 对象),但是我们没有引发属性更改事件,而是其余两个文本框自动更改。

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

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

它不会更新。所以我认为如果Person类实现了INotifyPropertyChanged,这种行为是正常的,但是现在该类没有实现接口,但它也更新了接口。如果您有任何线索,请告诉我原因。谢谢。

【问题讨论】:

    标签: wpf binding propertychanged updatesourcetrigger


    【解决方案1】:

    原因是PropertyDescriptor,看下面的线程, 有人问同样的问题:How does the data binding system know when a property is changed?

    这里有两个答案

    我认为神奇之处在于绑定系统的使用 PropertyDescriptor(SetValue 可能会引发一个 ValueChanged - PropertyDescriptor 可能是共享的,而事件是在 基于每个对象)。


    我不在 Microsoft,但我可以确认。如果 PropertyDescriptor 是 用于更新值,因为它会,然后是相关的变化 通知会自动传播。

    编辑
    您可以通过命名Person DataContext 对象来验证这一点

    <Window.DataContext>
        <local:Person x:Name="person"/>
    </Window.DataContext>
    

    并将以下代码添加到MainWindow ctor

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

    一旦您更改了三个 TextBox 中任何一个的值,您最终将进入事件处理程序 OnPropertyChanged。

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        【解决方案3】:

        嗯,正如你所说,你只需要实现INotifyPropertyChanged

        PropertyChanged 事件在您从代码 设置属性并且需要将此更改反映到您的 UI 时使用(UI 将包含 PropertyChanged 事件,感谢您的 UpdateSourceTrigger用户界面将被更新)。另一端(从 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");
              }
            }
        
        }
        

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

        【讨论】:

        • 那么你的意思是,如果我设置了propertychanged,UpdateTrigger会自动更新UI,而不仅仅是改变源实体对吧?
        • 而INotifyPropertyChanged接口只触发UI从后面的代码改变吧?
        • 就是这样,是的。基本上,您的 UpdateTrigger 正在等待捕获 PropertyChanged 事件以刷新绑定。由于您不会在任何地方触发它,因此它不会触发任何更新。你明白我在这里所说的意思:PropertyChanged 用于说“嘿 UI,请刷新自己,我已经改变了!” :)
        猜你喜欢
        • 1970-01-01
        • 2013-05-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-02-01
        • 2011-08-22
        • 2020-10-06
        • 1970-01-01
        相关资源
        最近更新 更多