首页 文章

在没有INotifyPropertyChanged的情况下更改通知? (摘自Pro#WPF in C#2010)

提问于
浏览
8

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

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

有人可以确认此功能有效吗?我正在尝试并且无法重现这种行为(我想知道这是否有效,然后我可以尝试使用System.Reflection.Emit来创建动态类型)

EDIT: 我应该澄清这里的重点是在没有实现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事件始终为null(我认为绑定引擎可能会在根据命名约定检测到它时自动订阅它) . MyEmployees只是一个ObservableCollection

有人可以确认作者提到的这个功能是否确实有效,如果我犯了错误?

EDIT: 为了那些认为我误解了文本的人的利益:

“您可以使用三种方法来解决此问题:

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

You can raise an event for each property. In this case, the event must have the name PropertyNameChanged (for example, UnitCostChanged). It’s up to you to fire the event when the property is changed.

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

3 回答

  • -2

    我会说在POCO中实现更改通知是非常有可能的,而不使用INotifyPropertyChanged或依赖属性,就像在书中声明的那样,除非我完全忽略了问题的要点 .

    如果在属性值发生更改时从POCO引发名为 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;
    }
    
  • 10

    您提到的模式适用于WPF以及Windows Forms(WinForms) .

  • 3

    不,使用WPF,您需要使用 DependencyPropertiesINotifyPropertyChanged . 对于收藏品, INotifyCollectionChanged 也可以做到这一点 .

相关问题