blu*_*utt 8 .net c# data-binding wpf inotifypropertychanged
在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"));
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
我将它绑定到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>
Run Code Online (Sandbox Code Playgroud)
FirstNameChanged事件始终为null(我认为绑定引擎可能会在根据命名约定检测到它时自动订阅它).MyEmployees只是一个ObservableCollection
有人可以确认作者提到的这个功能是否确实有效,如果我犯了错误?
编辑:为了任何认为我错误解释文本的人的利益:
"您可以使用三种方法来解决此问题:
您可以使用在第4章中学习的语法使Product类中的每个属性成为依赖项属性.(在这种情况下,您的类必须从DependencyObject派生.)虽然这种方法让WPF为您完成工作(这很好) ),它在窗口中具有视觉外观的元素类中最有意义.对于像Product这样的数据类,这不是最自然的方法.
您可以为每个房产举办活动.在这种情况下,事件必须具有名称PropertyNameChanged(例如,UnitCostChanged).您可以在更改属性时触发事件.
您可以实现System.ComponentModel.INotifyPropertyChanged接口,该接口需要名为PropertyChanged的单个事件.然后,只要属性发生更改,就必须引发PropertyChanged事件,并通过将属性名称作为字符串提供来指示哪个属性已更改.当属性发生变化时,仍然由您来提升此事件,但您不需要为每个属性定义单独的事件."
Pet*_*sen 10
我会说在POCO中实现更改通知是非常有可能的,而不使用INotifyPropertyChanged或依赖属性,就像在书中声明的那样,除非我完全忽略了问题的要点.
如果您在属性值发生更改时从POCO 更改了一个名为{Propertyname}的事件,WPF绑定系统将选择该项,并更新相关绑定.
看一下这个小程序进行演示 - 这是我能想到的最简单的事情,但我想它也适用于你的情况.
XAML:
<StackPanel>
<TextBlock Text="{Binding Name}" />
<Button Content="Change name" Click="changeNameClick" />
</StackPanel>
Run Code Online (Sandbox Code Playgroud)
代码隐藏:
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;
}
Run Code Online (Sandbox Code Playgroud)