为什么 INotifyPropertyChanged 不更新 XAML 中的变量?

发布于 2024-07-19 07:51:16 字数 4266 浏览 8 评论 0原文

我想模拟模型中的数据更改并使该数据反映在 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

拥有 2024-07-26 07:51:16

也许我没有得到你希望这段代码做的事情。

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

我在 WPF 视图

<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 代码似乎可以正常工作。

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

<Button DockPanel.Dock="Bottom" 
        x:Name="UpdateTime" 
        Click="UpdateTime_Click">
                 Update Activity Timestamp
 </Button>  

C# code-behind:

private void UpdateTime_Click(object sender, RoutedEventArgs e)
{
     Customer.GetCurrentCustomer().TimeOfMostRecentActivity = DateTime.Now;
}

I also changed Customer type to create a single instance for Current Customer

private static Customer _CurrentCustomer;

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

Now each time I click the button, the DateTime Property is modified and the view auto-updates due to the INotifyPropertyChanged mechanism. The code seems to be working AFAISee.

Bonjour°[大白 2024-07-26 07:51:16

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

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

private Timer _timer;

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

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

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:

private Timer _timer;

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

private void UpdateDateTime(object state)
{
    TimeOfMostRecentActivity = DateTime.Now;
}
烟雨凡馨 2024-07-26 07:51:16

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

You seem to be binding to Customer, and Customer doesn't implement INotifyPropertyChanged. Try implementing INotifyPropertyChanged on Customer, and see if that fixes it. This will require moving to manual properties (rather than automatically implemented properties) in order to raise the event.

裸钻 2024-07-26 07:51:16

你能检查一下 GetCurrentCustomer() 被调用了多少次吗? 也许它只是一直重新创建新实例。

Can you check how many times GetCurrentCustomer() gets called? Maybe it just re-creates new instances all the time.

喵星人汪星人 2024-07-26 07:51:16

您的客户类需要实现 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文