【问题标题】:Change notification without INotifyPropertyChanged? (excerpt from Pro WPF in C# 2010)没有 INotifyPropertyChanged 的​​更改通知? (摘自 C# 2010 中的 Pro WPF)
【发布时间】:2012-11-19 13:35:42
【问题描述】:

在阅读 C# 2010 中的 Pro WPF 时,作者写道:

“您可以为每个属性引发一个事件。在这种情况下,事件必须具有名称 PropertyNameChanged(例如,UnitCostChanged)。当属性更改时,由您来触发事件。”

有人可以确认此功能有效吗?我正在试验但无法重现这种行为(我想看看这是否有效,然后我可以使用 System.Reflection.Emit 进行一些试验以创建动态类型)

编辑:我应该澄清这里的重点是在不实现 INotifyPropertyChanged 的​​情况下实现更改通知,因为这就是本书所声称的

这是我正在测试的 POCO:

public class Employee
{
    private string _FirstName;
    public string FirstName 
    {
        get
        {
            return _FirstName;
        }
        set
        {
            if (_FirstName != value)
            {
                _FirstName = value;
                if (FirstNameChanged != null) 
                {
                    FirstNameChanged(this, new PropertyChangedEventArgs("FirstName"));
                }
            }
        }
    }
}

我将它绑定到 DataGrid 并在后台设置一个计时器,每隔几秒随机更新 FirstName 属性,但 DataGrid 永远不会触发

<DataGrid x:Name="dgEmployees" ItemsSource="{Binding ElementName=mainWindow, Path=MyEmployees}">
        <DataGrid.Columns>
            <DataGridTextColumn Header="FirstName" Binding="{Binding Path=FirstName}" />
        </DataGrid.Columns>
    </DataGrid>

FirstNameChanged 事件始终为空(我认为如果绑定引擎根据命名约定检测到它,它可能会自动订阅它)。 MyEmployees 只是一个 ObservableCollection

有人可以确认作者提到的此功能是否确实有效以及我是否犯了错误?

编辑:为了任何认为我误解了文字的人的利益:

"你可以使用三种方法来解决这个问题:

您可以使用 Product 类中的每个属性作为依赖属性 你在第 4 章学到的语法。(在这种情况下,你的类必须派生自 DependencyObject。)虽然这种方法让 WPF 为您完成工作 (这很好),它在元素中最有意义——具有视觉效果的类 出现在一个窗口中。对于像这样的数据类,这不是最自然的方法 产品。

您可以为每个属性引发一个事件。在这种情况下,事件必须具有 名称 PropertyNameChanged(例如 UnitCostChanged)。由你决定 当属性改变时触发事件。

您可以实现 System.ComponentModel.INotifyPropertyChanged 接口,它需要一个名为 PropertyChanged 的​​事件。那么你必须 每当属性更改时引发 PropertyChanged 事件并指示哪个 通过以字符串形式提供属性名称来更改属性。它仍然取决于 您可以在属性更改时引发此事件,但您不需要定义 每个属性的单独事件。”

【问题讨论】:

  • 不确定该语法是否有效,但您很确定需要将类装饰为实现 iNotifyPropertyChanged
  • 不,这正是我要避免的——在书中,它提到了 3 种技术是 a.) 使用 DependencyProperties b.) 使用 INotifyPropertyChanged(我已经很熟悉了)c .) 使用这种基于约定的方法,它不实现 INotifyPropertyChanged ..这就是我在这里测试的重点:)
  • 好的理解,但我认为这不是所声称的。您可以在没有 NotifyPropertyChanged 方法的情况下直接引发事件,但我认为您仍然需要实现 INotifyPropertyChanged。
  • 书中以互斥方式描述了这3种方法
  • 这些是在属性更改时通知的方法,但这并不意味着“绑定引擎”会自动订阅具有该约定的事件。绑定引擎仅(至少自动)与 Dependency Properties 和 INotifyPropertyChanged(或 INotifyCollectionChanged)一起工作

标签: c# .net wpf data-binding inotifypropertychanged


【解决方案1】:

我会说很有可能在不使用 INotifyPropertyChanged 或依赖属性的情况下在 POCO 中实现更改通知,就像书中声称的那样,除非我完全错过了问题的重点。

如果您在属性的值发生更改时从 POCO 中引发名为 {Propertyname}Changed 的事件,则 WPF 绑定系统将获取并更新相关的绑定。

查看这个小程序进行演示 - 这是我能想到的最简单的东西,但我想它也应该适用于你的情况。

XAML:

<StackPanel>
    <TextBlock Text="{Binding Name}" />
    <Button Content="Change name" Click="changeNameClick" />
</StackPanel>

代码隐藏:

public partial class Window1 : Window
{
    private SimpleObject so = new SimpleObject();

    public Window1()
    {
        InitializeComponent();

        this.so = new SimpleObject();
        so.Name = "Initial value";

        this.DataContext = so;

        var t = new DispatcherTimer(
            TimeSpan.FromSeconds(1), 
            DispatcherPriority.Normal,
            (s, e) => { this.so.Name = "Name changed at: " + DateTime.Now.ToString(); },
            Dispatcher);
    }

    private void changeNameClick(object sender, RoutedEventArgs e)
    {
        this.so.Name = "New value!!";
    }
}

public class SimpleObject
{
    private string mName = null;

    public string Name 
    {
        get { return mName; }
        set
        {
            if (mName != value)
            {
                mName = value;

                if (NameChanged != null)
                    NameChanged(this, EventArgs.Empty);
            }
        }
    }

    public event EventHandler NameChanged;
}

【讨论】:

  • 完美!我知道我没疯,哈哈。我的原始代码现在可以工作,但只有在我将“PropertyChangedEventHandler”更改为普通的“EventHandler”之后......知道为什么吗?这个“功能”是否记录在任何地方?太棒了,非常感谢你
  • 呵呵,不抱歉,我真的不知道为什么会这样。我记得前段时间听说过这个,但从未在我自己的代码中实际使用过它。而且我似乎在任何地方都找不到任何真正的文档,所以它可能不是一种非常广泛使用的技术..
  • 如果您有兴趣,我还有一些额外的见解 - 从检查来看,POCO 类型上的默认 PropertyDescriptor 是延迟加载的 ReflectPropertyDescriptor 实例 - 特别感兴趣的是 SupportsChangeEvents 布尔属性。如果类遵循 propertynameChanged 命名约定(尽管除非我使用普通的 EventHandler,否则它不起作用)或实现 INotifyPropertyChanged,则运行时将其设置为 true。缺少任何一个都会导致这是错误的。 msdn.microsoft.com/en-us/library/…
  • 啊,我明白了——这很有趣。希望这可以帮助您解决问题!
  • 有趣的讨论和一个不错的解决方案。我没有看过他们的代码,但我想 SupportsChangeEvents 属性的值是由对 EventHandler 类型和名称 Changed 的​​事件的搜索确定的。我想知道 WPF 是否正在使用 Wea​​kEventManager 进行订阅;不希望内存泄漏。
【解决方案2】:

您提到的模式适用于 WPF 以及 Windows 窗体 (WinForms)。

【讨论】:

  • 感谢您的链接!很高兴终于在 MSDN 上有一个明确的链接来描述它
【解决方案3】:

不,对于 WPF,您需要使用 DependencyPropertiesINotifyPropertyChanged。对于收藏,INotifyCollectionChanged 也可以解决问题。

【讨论】:

  • 显然你可以 - 查看答案。
  • 实际上有第 4 种方法 - 您始终可以手动提高 BindingExpression 上的 UpdateTarget() 方法,但我不确定我是否会计算
猜你喜欢
  • 2011-12-20
  • 2017-05-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-20
  • 1970-01-01
  • 2011-08-31
  • 2014-01-12
相关资源
最近更新 更多