8

在 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

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

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

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

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

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

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

4

3 回答 3

10

我会说很有可能在不使用 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;
}
于 2012-12-01T18:50:12.917 回答
3

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

  • WPF,请参阅: MSDN 上绑定源概述中的“提供更改通知”部分。

  • WinForms,请参阅如何:在 MSDN 上应用 PropertyNameChanged 模式。

于 2012-12-01T15:36:39.107 回答
-2

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

于 2012-12-01T15:27:55.087 回答