为什么 INotifyPropertyChanged 不更新 XAML 中的变量?
我想模拟模型中的数据更改并使该数据反映在 XAML 中。 据我了解,我需要实现 INotifyPropertyChanged。
但是,在下面的代码示例中,XAML 仅显示一次来自客户的数据,但日期和时间永远不会更改。
在以下示例中我必须更改什么才能使 XAML 在模型中发生更改时不断显示当前日期和时间?
特别是,我不明白 Binding 如何知道何时检查模型,每秒? 每秒10次? 没有它正在响应的事件。 我在这里缺少什么?
XAML:
<Window x:Class="TestBinding99382.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestBinding99382"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<ObjectDataProvider
x:Key="DataSourceCustomer"
ObjectType="{x:Type local:ShowCustomerViewModel}"
MethodName="GetCurrentCustomer"/>
</Window.Resources>
<DockPanel DataContext="{StaticResource DataSourceCustomer}">
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
<TextBlock Text="{Binding Path=FirstName}"/>
<TextBlock Text=" "/>
<TextBlock Text="{Binding Path=LastName}"/>
</StackPanel>
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
<TextBlock Text="{Binding Path=TimeOfMostRecentActivity}"/>
</StackPanel>
</DockPanel>
</Window>
代码隐藏:
using System.Windows;
using System.ComponentModel;
using System;
namespace TestBinding99382
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
}
//view model
public class ShowCustomerViewModel : INotifyPropertyChanged
{
private Customer _currentCustomer;
public Customer CurrentCustomer
{
get
{
return _currentCustomer;
}
set
{
_currentCustomer = value;
this.RaisePropertyChanged("CurrentCustomer");
}
}
public ShowCustomerViewModel()
{
_currentCustomer = Customer.GetCurrentCustomer();
}
public Customer GetCurrentCustomer()
{
return _currentCustomer;
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
//model
public class Customer : INotifyPropertyChanged
{
private string _firstName;
private string _lastName;
private DateTime _timeOfMostRecentActivity;
public string FirstName
{
get
{
return _firstName;
}
set
{
_firstName = value;
this.RaisePropertyChanged("FirstName");
}
}
public string LastName
{
get
{
return _lastName;
}
set
{
_lastName = value;
this.RaisePropertyChanged("LastName");
}
}
public DateTime TimeOfMostRecentActivity
{
get
{
return _timeOfMostRecentActivity;
}
set
{
_timeOfMostRecentActivity = value;
this.RaisePropertyChanged("TimeOfMostRecentActivity");
}
}
public static Customer GetCurrentCustomer()
{
return new Customer
{ FirstName = "Jim"
, LastName = "Smith"
, TimeOfMostRecentActivity = DateTime.Now};
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
}
I want to simulate data changing in the model and having that data be reflected in XAML. As I understand I need to implement INotifyPropertyChanged.
However, in the following code example, XAML displays the data from the customer only once but the date and time never changes.
What do I have to change in the following example to make XAML continually display the current date and time as it changes in the model?
In particular, I don't understand how the Binding would know when to check the model, every second? 10 times a second? There is no event that it is responding to. What am I missing here?
XAML:
<Window x:Class="TestBinding99382.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestBinding99382"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<ObjectDataProvider
x:Key="DataSourceCustomer"
ObjectType="{x:Type local:ShowCustomerViewModel}"
MethodName="GetCurrentCustomer"/>
</Window.Resources>
<DockPanel DataContext="{StaticResource DataSourceCustomer}">
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
<TextBlock Text="{Binding Path=FirstName}"/>
<TextBlock Text=" "/>
<TextBlock Text="{Binding Path=LastName}"/>
</StackPanel>
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
<TextBlock Text="{Binding Path=TimeOfMostRecentActivity}"/>
</StackPanel>
</DockPanel>
</Window>
Code Behind:
using System.Windows;
using System.ComponentModel;
using System;
namespace TestBinding99382
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
}
//view model
public class ShowCustomerViewModel : INotifyPropertyChanged
{
private Customer _currentCustomer;
public Customer CurrentCustomer
{
get
{
return _currentCustomer;
}
set
{
_currentCustomer = value;
this.RaisePropertyChanged("CurrentCustomer");
}
}
public ShowCustomerViewModel()
{
_currentCustomer = Customer.GetCurrentCustomer();
}
public Customer GetCurrentCustomer()
{
return _currentCustomer;
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
//model
public class Customer : INotifyPropertyChanged
{
private string _firstName;
private string _lastName;
private DateTime _timeOfMostRecentActivity;
public string FirstName
{
get
{
return _firstName;
}
set
{
_firstName = value;
this.RaisePropertyChanged("FirstName");
}
}
public string LastName
{
get
{
return _lastName;
}
set
{
_lastName = value;
this.RaisePropertyChanged("LastName");
}
}
public DateTime TimeOfMostRecentActivity
{
get
{
return _timeOfMostRecentActivity;
}
set
{
_timeOfMostRecentActivity = value;
this.RaisePropertyChanged("TimeOfMostRecentActivity");
}
}
public static Customer GetCurrentCustomer()
{
return new Customer
{ FirstName = "Jim"
, LastName = "Smith"
, TimeOfMostRecentActivity = DateTime.Now};
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
也许我没有得到你希望这段代码做的事情。
您已经创建了一个实现 INotifyPropertyChanged 的客户对象。 您还有另一个类,它是 XAML 访问实例的工厂。
现在,您创建一个具有预定义属性的 Customer 实例。 视图显示它们。 除非您以某种方式更改属性,否则视图将不会更新。
我在 WPF 视图
C# 代码隐藏中添加了一个按钮:
我还更改了客户类型,为当前客户创建单个实例。
现在,每次单击该按钮时,
DateTime
属性都会被修改,并且视图自动-由于INotifyPropertyChanged
机制而更新。 AFAISee 代码似乎可以正常工作。Maybe I'm not getting what you wish this code to do.
You have created a Customer Object which implements INotifyPropertyChanged. You have another class which is a factory for the XAML to get to the instance.
Now you create a Customer instance with predefined properties. The View displays them. Unless you change the properties somehow, the View will not update.
I added a button to your WPF View
C# code-behind:
I also changed Customer type to create a single instance for Current Customer
Now each time I click the button, the
DateTime
Property is modified and the view auto-updates due to theINotifyPropertyChanged
mechanism. The code seems to be working AFAISee.您的代码工作正常。 当前日期和时间不会神奇地自动更新。 你必须实现一些计时器来更新它。
例如,您可以将其添加到您的 Customer 类中:
Your code is working correctly. The current date and time will not update automatically by magic. You have to implement some timer to update it.
For exemple you could add this to your Customer class:
您似乎绑定到
Customer
,并且Customer
没有实现INotifyPropertyChanged
。 尝试在Customer
上实施INotifyPropertyChanged
,看看是否可以解决问题。 这将需要移动到手动属性(而不是自动实现的属性)才能引发事件。You seem to be binding to
Customer
, andCustomer
doesn't implementINotifyPropertyChanged
. Try implementingINotifyPropertyChanged
onCustomer
, and see if that fixes it. This will require moving to manual properties (rather than automatically implemented properties) in order to raise the event.你能检查一下 GetCurrentCustomer() 被调用了多少次吗? 也许它只是一直重新创建新实例。
Can you check how many times GetCurrentCustomer() gets called? Maybe it just re-creates new instances all the time.
您的客户类需要实现 INotifyPropertyChanged,并且您需要在客户属性的 setter 方法期间调用该事件。
编辑:再次查看您的代码,我想知道您的 ShowCustomerViewModel 类是否需要侦听 _currentCustomer PropertyChanged 事件并将其作为自己的 PropertyChangedEvent 转发。 值得一试。
Your customer class needs to implement INotifyPropertyChanged and you need to invoke the event during the setter methods of the properties of Customers.
Edit: Have looked at you code again, I wonder whether your ShowCustomerViewModel class needs to listen to the _currentCustomer PropertyChanged event and forward it as its own PropertyChangedEvent. Worth a shot.