C# 为什么INotifyPropertyChanged没有更新XAML中的变量?

C# 为什么INotifyPropertyChanged没有更新XAML中的变量?,c#,wpf,xaml,data-binding,inotifypropertychanged,C#,Wpf,Xaml,Data Binding,Inotifypropertychanged,我想模拟模型中的数据变化,并让这些数据反映在XAML中。据我所知,我需要实现INotifyPropertyChanged 但是,在下面的代码示例中,XAML只显示来自客户的数据一次,但日期和时间从未更改 在下面的示例中,我必须更改什么才能使XAML在模型中更改时持续显示当前日期和时间? 特别是,我不明白绑定如何知道何时每秒检查模型?每秒10次?没有它正在响应的事件。我错过了什么 XAML: <Window x:Class="TestBinding99382.Window1" xml

我想模拟模型中的数据变化,并让这些数据反映在XAML中。据我所知,我需要实现INotifyPropertyChanged

但是,在下面的代码示例中,XAML只显示来自客户的数据一次,但日期和时间从未更改

在下面的示例中,我必须更改什么才能使XAML在模型中更改时持续显示当前日期和时间?

特别是,我不明白绑定如何知道何时每秒检查模型?每秒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));
            }
        }
    }
}

您似乎正在绑定到
Customer
,而
Customer
未实现
INotifyPropertyChanged
。尝试在
Customer
上实现
INotifyPropertyChanged
,看看这是否能解决问题。这将需要移动到手动属性(而不是自动实现的属性)以引发事件。

您的客户类需要实现INotifyPropertyChanged,并且您需要在客户属性的setter方法期间调用事件


编辑:再次查看代码后,我想知道ShowCustomerServiceWModel类是否需要侦听_CurrentCustomerPropertyChanged事件,并将其作为自己的PropertyChangedEvent转发。值得一试。

您能检查调用GetCurrentCustomer()的次数吗?可能它只是一直在重新创建新实例。

您的代码工作正常。当前日期和时间不会通过magic自动更新。您必须实现一些计时器来更新它

例如,您可以将其添加到Customer类中:

private Timer _timer;

public Customer()
{
    _timer = new Timer(UpdateDateTime, null, 0, 1000);
}

private void UpdateDateTime(object state)
{
    TimeOfMostRecentActivity = DateTime.Now;
}

也许我没有得到你想要的代码

您已经创建了一个实现INotifyPropertyChanged的Customer对象。您还有另一个类,它是XAML访问实例的工厂。 现在,您可以创建一个具有预定义属性的客户实例。视图将显示它们。除非以某种方式更改属性,否则视图将不会更新

我在WPF视图中添加了一个按钮

<Button DockPanel.Dock="Bottom" 
        x:Name="UpdateTime" 
        Click="UpdateTime_Click">
                 Update Activity Timestamp
 </Button>  
我还更改了客户类型,为当前客户创建了一个实例

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
机制,视图会自动更新。代码似乎正在运行

实际上是这样的:谢谢,但是我修改了上面的代码,这样Customer类也实现了INotifyChanged,但是仍然不起作用。我还必须做什么?据我所知,我的模型类正在实现INotifyPropertyChanged,与您的相同,您是否可能在XAML中以不同的方式绑定它?并且您正在setters中引发事件?是的,与上面的代码一样:this.RaisePropertyChanged(“TimeOfMosterRecentActivity”);这就是你的意思吗?谢谢,但是我修改了上面的代码,这样Customer类也实现了INotifyChanged,但是仍然不起作用。我还必须做什么呢?但是绑定对象如何知道本例中的“时间已更改”?它是否经常重新实例化并观察模型?我放置了一个控制台。在ViewModel的GetCurrentCustomer()中写入,它会被调用一次。这正是我所期望的,但无论你在哪里读到关于XAML绑定,MVVM,最大的特点是XAML将根据模型中的更改进行自我更新,这就是我在这里试图重新创建的,以便我可以在此基础上进行构建。此外,CustomServiceWModel不需要实现INotifyPropertyChanged。谢谢,这确实帮助了我向前迈进,我在这里发布了一个根据您的建议创建的示例:您是否需要与Dispatcher同步属性更改,因为您导致的UI更改来自与UI线程不同的线程?据我所知,在引发PropertyChanged之后,WPF数据绑定将在UI线程上获取值。业务对象不知道WPF应用程序上使用了该值。因此,不,我们不应该与WPF调度程序同步。谢谢,计时器是我尝试做的一个很酷的补充,我在这里发布了一个使用它的完整示例:
private static Customer _CurrentCustomer;

public static Customer GetCurrentCustomer()
{
    if (null == _CurrentCustomer)
    {
        _CurrentCustomer = new Customer 
        {   FirstName = "Jim"
           , LastName = "Smith"
           , TimeOfMostRecentActivity = DateTime.Now 
         };
    }
         return _CurrentCustomer;
}