绑定DispatcherTimer不要忽略它在View上的价值

时间:2019-05-05 07:05:52

标签: c# wpf xaml mvvm

在UserInteractiton类中,我创建了TestTimer类的实例,计时器位于其中。我运行它,并希望在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; }
}

模型

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

1 个答案:

答案 0 :(得分:2)

您应该引发INotifyPropertyChanged.PropertyChanged事件,以通知View您的视图模型的某些属性已更改。 INotifyPropertyChanged的基本实现意味着您有一种引发此事件的方法:

    public event PropertyChangedEventHandler PropertyChanged;

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

并且您应该从属性的设置方法中调用此方法以使绑定正常工作:

    private string _timeFormat;

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

如果要用[CallerMemberName]属性标记propertyName参数,则可以忽略将参数传递给OnPropertyChanged方法:

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

下面的TestTimer类的完整代码:

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