Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Time Ticking in C# WPF MVVM

I am doing a program, which must have a clock hanging every second, main problem is that I am beginner in WPF and MVVM :)

But otherwise my clock is running just not refreshing. I have special class for only Time and Date purpose.

Here is my code:

TimeDate class:

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

    }
}

ViewModel:

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

And also NotifyProperty in ViewModelBase:

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

}

What to do, that Clock will refresh every second? Please help

like image 508
Pukaai Avatar asked Jul 01 '15 11:07

Pukaai


2 Answers

As MSDN:

Reasons for using a DispatcherTimer opposed to a System.Timers.Timer are that the DispatcherTimer runs on the same thread as the Dispatcher and a DispatcherPriority can be set on the DispatcherTimer.

I make shorter example:

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>

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

enter image description here

Hope this help.

like image 129
hungndv Avatar answered Sep 24 '22 07:09

hungndv


You have to specify the DispatcherTimer as a field in your viewmodel class, not just as a local variable in ctor.

Garbage Collector will destroy all local variables when they are out of scope.

Here is my implementation of the clock :)

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}}" />
like image 27
Liero Avatar answered Sep 21 '22 07:09

Liero