Amazing User
Amazing User

Reputation: 3563

Binding of DispatcherTimer don't show it's value on View

In the UserInteractiton class I created an instance of the TestTimer class, in which the timer is located. I run it and I want to display the value of this timer in View, but for some reason nothing is displayed.

View

<Grid>
    <TextBlock Name="textTimeMiddle" TextWrapping="Wrap"
       Text="{Binding TestTimer.TimeFormat, UpdateSourceTrigger=PropertyChanged}"/>
</Grid>

VievModel

public class UserInteractiton : INotifyPropertyChanged
{
    public UserInteractiton()
    {
        TestTimer = new TestTimer();
    }

    public TestTimer TestTimer { get; private set; }
}

Model

public class TestTimer : INotifyPropertyChanged
    {
        private string timeFormat;
        public string TimeFormat
        {
            get { return timeFormat; }
            set
            {
                timeFormat = value;
                OnPropertyChanged();
            }
        }

        public TestTimer()
        {
            StartTimer();
        }

        public void StartTimer()
        {
            Timer = new DispatcherTimer();
            Timer.Interval = new TimeSpan(0, 0, 1);
            Timer.Tick += TimerTick;
            Timer.Start();
        }

        private async void TimerTick(object sender, EventArgs e)
        {
            await Task.Run(() => TimerCycle());
        }

        private void TimerCycle()
        {
            for (;;)
            {
                if (Seconds > 59)
                {
                    Seconds = 0;
                    Minutes++;

                    if (Minutes > 59)
                    {
                        Minutes = 0;
                        Hours++;

                        if (Hours > 23)
                            Hours = 0;
                    }
                }
                Seconds++;

                timeFormat = string.Format("{0:00}:{1:00}:{2:00}",
                    Hours, Minutes, Seconds);
                Thread.Sleep(200);
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged([CallerMemberName]string prop = "")
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(prop));
        }
    }

Upvotes: 0

Views: 204

Answers (1)

s4n4etti
s4n4etti

Reputation: 71

You should raise INotifyPropertyChanged.PropertyChanged event to notify view that some properties of your view-model has been changed. The basic implementation of INotifyPropertyChanged implies that you have a method to raise this event:

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

And you should invoke this method from property's setter to make binding work properly:

    private string _timeFormat;

    public string TimeFormat
    {
        get { return _timeFormat; }
        private set
        {
            _timeFormat = value;
            OnPropertyChanged(nameof(TimeFormat));
        }
    }

If you would mark propertyName parametr with [CallerMemberName] attribute you could ignore passing the argument to OnPropertyChanged method:

    public string TimeFormat
    {
        get { return _timeFormat; }
        private set
        {
            _timeFormat = value;
            OnPropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

Full code of your TestTimer class below:

    public class TestTimer : INotifyPropertyChanged
    {
        private string _timeFormat;
        public int Minutes { get; private set; }
        public int Seconds { get; private set; }
        public int Hours { get; private set; }
        public DispatcherTimer Timer { get; private set; }
        public string TimeFormat
        {
            get { return _timeFormat; }
            private set
            {
                _timeFormat = value;
                OnPropertyChanged(nameof(TimeFormat));
            }
        }

        public TestTimer()
        {
            StartTimer();
        }

        public void StartTimer()
        {
            Timer = new DispatcherTimer();
            Timer.Interval = new TimeSpan(0, 0, 1);
            Timer.Tick += TimerTick;
            Timer.Start();
        }

        private async void TimerTick(object sender, EventArgs e)
        {
            await Task.Run(() => TimerCycle());
        }

        private void TimerCycle()
        {
            for (; ; )
            {
                if (Seconds > 59)
                {
                    Seconds = 0;
                    Minutes++;

                    if (Minutes > 59)
                    {
                        Minutes = 0;
                        Hours++;

                        if (Hours > 23)
                            Hours = 0;
                    }
                }
                Seconds++;

                TimeFormat = string.Format("{0:00}:{1:00}:{2:00}",
                    Hours, Minutes, Seconds);
                Thread.Sleep(200);
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

Upvotes: 2

Related Questions