Question

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));
            }
        }
    }
}
Was it helpful?

Solution

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.

OTHER TIPS

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;
}

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.

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

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top