简体   繁体   中英

Timer in MVVM for Windows Phone 8 and Windows 8

I have a Universal/Portable C# library for Windows Phone 8 and Windows 8. The library will be referenced by apps for each platform. In the library is a view model and I'm trying to put a timer in the view model. The only "Timer" available in the library for both platforms is the System.Threading.Timer (no DispatcherTimer). However, I cannot work around the cross threading issues. Is there a way to do this or do I have to create a timer in each app in the page code behind?


public class DefaultViewModel : INotifyPropertyChanged
{
    System.Threading.Timer _Timer;

    public DefaultViewModel()
    {
        this.ToggleStartStopCommand = new Command(ToggleStartStop, true);
    }

    private TimeSpan _Duration;
    public TimeSpan Duration
    {
        get { return this._Duration; }
        set
        {
            if (value != this._Duration)
            {
                this._Duration = value;
                this.RaisePropertyChanged("Duration"); // Error occurs here
            }
        }
    }

    private bool _IsRunning;
    public bool IsRunning
    {
        get { return this._IsRunning; }
        set
        {
            if (value != this._IsRunning)
            {
                this._IsRunning = value;
                this.RaisePropertyChanged("IsRunning");
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public virtual void RaisePropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
        if (null != propertyChanged)
            propertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    public void Start()
    {
        this.IsRunning = true;
        this._Timer = new Timer(TimerTick, this, 0, 1000);
    }

    private DateTime _StartTime;
    public DateTime StartTime
    {
        get { return this._StartTime; }
        set
        {
            if (value != this._StartTime)
            {
                this._StartTime = value;
                this.RaisePropertyChanged("StartTime");
            }
        }
    }

    public void Stop()
    {
        this._Timer.Dispose();
        this.IsRunning = false;
    }

    private void TimerTick(object o)
    {
        var defaultViewModel = (DefaultViewModel)o;
        defaultViewModel.Duration = DateTime.Now - defaultViewModel.StartTime;
    }

    public void ToggleStartStop()
    {
        if (this.IsRunning)
            this.Stop();
        else
            this.Start();
    }

    public Command ToggleStartStopCommand { get; private set; }
}

Two potential solutions:

  1. If you're targeting Windows 8 and Windows Phone 8.1 (not Phone 8.0 Silverlight), consider using a Universal App containing a Shared Project instead of a Portable Class Library to host your Viewmodels. Shared projects are only compatible with WinRT projects, but support the full WinRT framework. In that case, it should not be a problem to instantiate a DispatcherTimer directly within the Viewmodel.
  2. Otherwise (within a real Portable Class Library), I'm afraid the only way is to create an interface within the PCL that provides the most important timer functions, and two platform-specific timer classes that implement this interface. In practice, these two implementations will be identical except for the using statements at the beginning of the file, because Windows Phone Silverlight's DispatcherTimer lives within the System.Windows.Threading namespace while on WinRT it's located at Windows.UI.Xaml but both have the same functionality - so it's basically a copy/paste job.

    I've realized such a splitted implementation as part of the MVVMbasics framework, maybe the sources avaiable at Codeplex are of any help!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM