WPF 中 PropertyChanged UpdataSourceTrigger 的奇怪行为

发布于 2024-11-29 00:06:44 字数 1309 浏览 0 评论 0原文

我有一个像这样的实体:

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,这种行为是正常的,但现在该类没有实现该接口,但它也更新了接口。如果您有任何线索,请告诉我原因。谢谢。

I have an entity like this:

public class Person
{
    public string Name { get; set; }

    public Person()
    {
        Name = "Godspeed";
    }
}

Then I have three textbox and a button in 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>

The weird thing is that, the entity "Person" doesn't implement the INotifyPropertyChanged, but when one text box is changed, it modifies the source(Person object), but we didn't raised the property changed event but the rest two textboxes automatically changed.

When the button clicks, we update the source directly by code like:

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

It doesn't update. So what I think is that if the Person class implement the INotifyPropertyChanged, this behavior is normal, but now the class doesn't implement the interface, but it update the interface too. Please info me the reason if you have some clue. Thanks.

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

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

发布评论

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

评论(3

虚拟世界 2024-12-06 00:06:44

原因是PropertyDescriptor,请参阅以下线程,
正在提出同样的问题: 数据绑定系统如何知道属性何时更改?

这是两个答案

我认为神奇之处在于绑定系统的使用
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 中。

The reason is PropertyDescriptor, see the following thread,
the same question is being asked: How does the data binding system know when a property is changed?

Here is two of the answers

I think the magic lies in the binding system's use of
PropertyDescriptor (SetValue presumably raises a ValueChanged - the
PropertyDescriptor is likely shared, while the events are raised on a
per-object basis).


I'm not at Microsoft, but I can confirm it. If PropertyDescriptor is
used to update the value, as it will be, then relevant change
notifications are automatically propagated.

Edit
You can verify this by naming the Person DataContext object

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

and add the following code to the 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");
}

Once you change the value on any of the three TextBoxes, you'll end up in the event handler OnPropertyChanged.

¢好甜 2024-12-06 00:06:44

好吧,正如您所说,您只需实现 INotifyPropertyChanged

当您从代码设置属性并需要反映这一点时,将使用 PropertyChanged 事件更改您的 UI(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");
      }
    }

}

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

Well, as you said, you just have to implement INotifyPropertyChanged

The PropertyChanged event is used when you set a property from code and need to reflect this change to your UI (UI will cath the PropertyChanged event, and thanks to your UpdateSourceTrigger the UI will be updated). The other side (changing from UI) does not need any PropertyChanged, this is why you get this behavior

Just try it like that:

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

}

Using this code, when you set the Name, the PropertyChanged event will be fired and therefore update UI accordingly :)

九厘米的零° 2024-12-06 00:06:44

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

It works not only with updatesourcetrigger=propertychanged, but with default (lost focus) value too. In addition to what @Meleak said, I want to point that it is good behaviour. Any changes made by ui are propagated to all binding targets. Binding engine wants to propagate this changes to all controls at once. If you make changes through code, and not implement INotifyPropertyChanged - changes made from code are not reflected at all. Again, for all controls with the same binding source. All controls works in the synchronized way with such implementation.

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