Почему 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));
}
}
}
}
5 ответов
Возможно, я не понимаю, что вы хотите, чтобы этот код делал.
Вы создали объект Customer, который реализует INotifyPropertyChanged. У вас есть другой класс, который является фабрикой для XAML, чтобы получить к экземпляру. Теперь вы создаете экземпляр Customer с предопределенными свойствами. Вид отображает их. Если вы не измените свойства каким-либо образом, представление не будет обновлено.
Я добавил кнопку в ваш WPF View
<Button DockPanel.Dock="Bottom"
x:Name="UpdateTime"
Click="UpdateTime_Click">
Update Activity Timestamp
</Button>
C# код-позади:
private void UpdateTime_Click(object sender, RoutedEventArgs e)
{
Customer.GetCurrentCustomer().TimeOfMostRecentActivity = DateTime.Now;
}
Я также изменил тип клиента, чтобы создать один экземпляр для текущего клиента
private static Customer _CurrentCustomer;
public static Customer GetCurrentCustomer()
{
if (null == _CurrentCustomer)
{
_CurrentCustomer = new Customer
{ FirstName = "Jim"
, LastName = "Smith"
, TimeOfMostRecentActivity = DateTime.Now
};
}
return _CurrentCustomer;
}
Теперь каждый раз, когда я нажимаю кнопку, DateTime
Свойство изменено, и представление автоматически обновляется из-за INotifyPropertyChanged
механизм. Код, кажется, работает AFAISee.
Ваш код работает правильно. Текущая дата и время не будут обновляться автоматически по волшебству. Вы должны реализовать некоторый таймер для его обновления.
Например, вы можете добавить это в свой класс Customer:
private Timer _timer;
public Customer()
{
_timer = new Timer(UpdateDateTime, null, 0, 1000);
}
private void UpdateDateTime(object state)
{
TimeOfMostRecentActivity = DateTime.Now;
}
Можете ли вы проверить, сколько раз вызывается GetCurrentCustomer()? Может быть, он просто постоянно создает новые экземпляры.
Вашему клиентскому классу необходимо реализовать INotifyPropertyChanged, и вам нужно вызывать событие во время методов установки свойств Customer.
Изменить: снова посмотрел на ваш код, мне интересно, должен ли ваш класс ShowCustomerViewModel прослушивать событие _currentCustomer PropertyChanged и пересылать его как свой собственный PropertyChangedEvent. Стоит выстрел.
Вы, кажется, привязаны к Customer
, а также Customer
не реализует INotifyPropertyChanged
, Попробуйте реализовать INotifyPropertyChanged
на Customer
и посмотрим, исправит ли это. Это потребует перехода к ручным свойствам (а не автоматически реализованным свойствам), чтобы вызвать событие.