C#WPF MVVM中的时间滴答

Puk*_*aai 5 c# wpf time mvvm ticker

我正在做一个程序,每秒必须挂一个时钟,主要问题是我是WPF和MVVM的初学者:)

但是否则我的时钟运行起来并不令人耳目一新 我只有时间和日期目的的特殊课程.

这是我的代码:

TimeDate类:

public class TimeDate : ViewModelBase
{

    public string SystemTimeHours;
    string SystemTimeLong;
    string SystemDateLong;
    string SystemTimeZoneLong;

    string SystemTimeShort;
    string SystemDateShort;
    string SystemTimeZoneShort;



    public void InitializeTimer()
    {

        DispatcherTimer timer = new DispatcherTimer();
        timer.Interval = TimeSpan.FromSeconds(1);
        timer.Tick += new EventHandler(timer_Tick);
        timer.Start();
    }

    void timer_Tick(object sender, EventArgs e)
    {

        SystemTimeHours = DateTime.Now.ToString("HH:mm tt");

    }
}
Run Code Online (Sandbox Code Playgroud)

视图模型:

public class ViewModel : ViewModelBase
{
    public ViewModel()
    {
        TimeDate td = new TimeDate();
        td.InitializeTimer();
        HoursTextBox = td.SystemTimeHours;

    }



    private string _hourstextbox;
    public string HoursTextBox
    {
        get
        { return _hourstextbox; }
        set
        {
            if (value != _hourstextbox)
            {
                _hourstextbox = value;
                NotifyPropertyChanged("HoursTextBox");
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

以及ViewModelBase中的NotifyProperty:

public class ViewModelBase : INotifyPropertyChanged, IDisposable
{
    #region Constructor

    protected ViewModelBase()
    {
    }

    #endregion // Constructor

    #region DisplayName


    public virtual string DisplayName { get; protected set; }

    #endregion // DisplayName

    #region Debugging Aides

    [Conditional("DEBUG")]
    [DebuggerStepThrough]
    public void VerifyPropertyName(string propertyName)
    {
        // Verify that the property name matches a real,  
        // public, instance property on this object.
        if (TypeDescriptor.GetProperties(this)[propertyName] == null)
        {
            string msg = "Invalid property name: " + propertyName;

            if (this.ThrowOnInvalidPropertyName)
                throw new Exception(msg);
            else
                Debug.Fail(msg);
        }
    }


    protected virtual bool ThrowOnInvalidPropertyName { get; private set; }

    #endregion // Debugging Aides

    #region INotifyPropertyChanged Members


    public event PropertyChangedEventHandler PropertyChanged;


    /// <param name="propertyName">The property that has a new value.</param>
    protected virtual void NotifyPropertyChanged(string propertyName)
    {
        this.VerifyPropertyName(propertyName);

        PropertyChangedEventHandler handler = this.PropertyChanged;
        if (handler != null)
        {
            var e = new PropertyChangedEventArgs(propertyName);
            handler(this, e);
        }
    }

    protected virtual void NotifyPropertyChangedAll(object inOjbect)
    {
        foreach (PropertyInfo pi in inOjbect.GetType().GetProperties())
        {
            NotifyPropertyChanged(pi.Name);
        }
    }
    public virtual void Refresh()
    {
        NotifyPropertyChangedAll(this);
    }
    #endregion // INotifyPropertyChanged Members

    #region IDisposable Members

    public void Dispose()
    {
        this.OnDispose();
    }

    /// <summary>
    /// Child classes can override this method to perform 
    /// clean-up logic, such as removing event handlers.
    /// </summary>
    protected virtual void OnDispose()
    {
    }


    /// </summary>
    ~ViewModelBase()
    {
        string msg = string.Format("{0} ({1}) ({2}) Finalized", this.GetType().Name, this.DisplayName, this.GetHashCode());
        System.Diagnostics.Debug.WriteLine(msg);
    }


    #endregion // IDisposable Members

}
Run Code Online (Sandbox Code Playgroud)

怎么办,那个时钟会每秒刷新一次?请帮忙

hun*_*ndv 6

正如MSDN:

使用 DispatcherTimer 而不是 System.Timers.Timer 的原因是 DispatcherTimer 与 Dispatcher 在同一线程上运行,并且可以在 DispatcherTimer 上设置 DispatcherPriority。

我举个更短的例子:

XAML:

<Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="98" Width="128"
            xmlns:local="clr-namespace:WpfApplication1">
    <Window.DataContext>
        <!-- This will auto create an instance of ViewModel -->
        <local:ViewModel /> 
    </Window.DataContext>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Label Name="lblTimer" Grid.Row="1" Content="{Binding Path=CurrentTime}"></Label>
    </Grid>
</Window>
Run Code Online (Sandbox Code Playgroud)

CS:

namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }

    public class ViewModel : ViewModelBase
    {
        private string _currentTime;

        public DispatcherTimer _timer;

        public string CurrentTime
        {
            get
            {
                return this._currentTime;
            }
            set
            {
                if (_currentTime == value)
                    return;
                _currentTime = value;
                OnPropertyChanged("CurrentTime");
            }
        }

        public ViewModel()
        {
            _timer = new DispatcherTimer(DispatcherPriority.Render);
            _timer.Interval = TimeSpan.FromSeconds(1);
            _timer.Tick += (sender, args) =>
                           {
                               CurrentTime = DateTime.Now.ToLongTimeString();
                           };
            _timer.Start();
        }
    }

    public class ViewModelBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName = null)
        {
            var handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

希望这有帮助。


Lie*_*ero 5

您必须将 DispatcherTimer 指定为 viewmodel 类中的字段,而不仅仅是 ctor 中的局部变量。

当局部变量超出范围时,垃圾收集器将销毁它们。

这是我的时钟实现:)

public class MainWindowViewModel : ViewModelBase
{
    private readonly DispatcherTimer _timer;

    public MainWindowViewModel()
    {
        _timer = new DispatcherTimer {Interval = TimeSpan.FromSeconds(1)};
        _timer.Start();
        _timer.Tick += (o, e) => OnPropertyChanged("CurrentTime");
    }

    public DateTime CurrentTime { get { return DateTime.Now; } }
}

<TextBlock Text="{Binding CurrentTime, StringFormat={}{0:HH:mm tt}}" />
Run Code Online (Sandbox Code Playgroud)