【问题标题】:Why does the binding update without implementing INotifyPropertyChanged?为什么绑定更新没有实现 INotifyPropertyChanged?
【发布时间】:2021-10-02 05:03:21
【问题描述】:

我创建了一个 ViewModel 并将其属性绑定到 UI 上的两个文本框。当我更改 first 的值并 将焦点移出文本框 时,另一个文本框的值会发生变化,但我没有实现 INotifyPropertyChanged。这是如何工作的?

以下是 XAML

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication1"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <local:ViewModel />
    </Window.DataContext>
    <StackPanel>
        <TextBox Text="{Binding Name}" />
        <TextBox Text="{Binding Name}" />
    </StackPanel>
</Window>

下面是我的 ViewModel

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

【问题讨论】:

    标签: wpf xaml data-binding


    【解决方案1】:

    我测试过,你是对的。现在我在网上搜索,找到了this

    抱歉这么久才回复,实际上你遇到了另一个WPF的隐藏方面,那就是WPF的数据绑定引擎将数据绑定到PropertyDescriptor实例如果源对象是普通 CLR 对象并且不实现 INotifyPropertyChanged 接口,则源属性。并且数据绑定引擎将尝试通过 PropertyDescriptor.AddValueChanged() 方法订阅属性更改事件。而当目标数据绑定元素改变属性值时,数据绑定引擎会调用 PropertyDescriptor.SetValue() 方法将改变后的值传回源属性,同时会引发 ValueChanged 事件通知其他订阅者(在这种情况下,其他订阅者将是 ListBox 中的 TextBlock。

    如果您正在实施 INotifyPropertyChanged,您将完全负责在需要将数据绑定到 UI 的属性的每个设置器中实施更改通知。否则,更改将不会像您期望的那样同步。

    希望这能把事情弄清楚一点。

    所以基本上你可以这样做,只要它是一个普通的 CLR 对象。非常整洁但完全出乎意料 - 过去几年我做了一些 WPF 工作。你永远不会停止学习新事物,对吧?

    正如 Hasan Khan 所建议的,这里是 another link,这是一篇关于这个主题的非常有趣的文章。

    注意这仅在使用绑定时有效。如果您从代码更新值,则更改不会收到通知。 [...]

    WPF 在绑定时使用重量更轻的 PropertyInfo 类。如果显式实现 INotifyPropertyChanged,则 WPF 需要做的就是调用 PropertyInfo.GetValue 方法来获取最新值。这比获取所有描述符要少得多。描述符最终花费了属性信息类内存的 4 倍。 [...]

    实现 INotifyPropertyChanged 可能是相当乏味的开发工作。但是,您需要根据 WPF 应用程序的运行时占用空间(内存和 CPU)权衡该工作。 自己实现 INPC 将节省运行时 CPU 和内存

    编辑:

    更新这个,因为我仍然不时从这里获得 cmets 和 upvotes,所以它显然仍然相关,即使我自己已经有一段时间没有使用 WPF。但是,如 cmets 中所述,请注意这可能会导致 memory leaks。据说它对反射的使用也很重,这也被提到了。

    【讨论】:

    • +1 我多年来一直在使用 WPF,但从未意识到这一点 - 也许您应该将它放在此处的“隐藏 WPF 功能”线程中?
    • 有趣。我不知道我现在也在 WPF 中工作了很长一段时间。
    • @AngelWPF - Hasan Khan 发布的链接解释说,如果从 UI 更改属性,它只会导致 UI 更新 - 不会传播代码的更改
    • 我已经用我认为有价值的所有相关信息更新了我的答案,以便快速浏览。又一天,又一个秘密暴露了!我喜欢 StackOverflow :)
    • 所以,人们应该知道,如果你不在 CLR 对象上实现 INotifyPropertyChanged ......你会导致内存泄漏。见cplotts.com/2009/04/14/wpf-memory-leaks
    【解决方案2】:

    我可以解释为什么当焦点改变时属性会更新:所有Bindings 都有一个UpdateSourceTrigger 属性,它指示何时源属性将被更新。此默认值在每个 DependencyProperty 上定义,TextBox.Text 属性设置为 LostFocus,这意味着当控件失去焦点时将更新该属性。

    我相信 UrbanEsc 的回答解释了为什么值会被更新

    【讨论】:

      【解决方案3】:

      我刚刚发现这也适用于 WinForms,有点:/

      public class Test
      {
          public bool IsEnabled { get; set; }
      }
      
      var test = new Test();
      var btn = new Button { Enabled = false, Text = "Button" };
      var binding = new Binding("Enabled", test, "IsEnabled");
      btn.DataBindings.Add(binding);
      var frm = new Form();
      frm.Controls.Add(btn);
      test.IsEnabled = true;
      Application.Run(frm);
      

      奇怪的是,这并没有禁用按钮:

      btn.Enabled = false;
      

      这样做:

      test.IsEnabled = false;
      

      【讨论】:

        猜你喜欢
        • 2021-02-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-04-21
        • 2015-09-29
        相关资源
        最近更新 更多