Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Timer in View Model

I have service class in external assembly, I inject this class in view model class with MEF. I need call service method every 3-4 seconds from view model.

I get from service new data as Dictionary. This Dictionary is bind to listbox in view. And I need refresh with this data listbox in view.

In my solution I use DispatcherTimer, but I am absolute begginer in calibur.micto also MVVM and WPF. I don’t know what is a suitable solution in my case. So if someone have advance I will be gratefull.

My solution is here:

[Export("MainScreen", typeof(IMainViewModel))]
    public class MainViewModel : Screen, IMainViewModel
    {

        [Import]
        private Service _service;//import with MEF from external assembly
        [Import]
        private Connection _conn;//import with MEF from external assembly

        //this dictionary is bind to the listbox in view
        private MyObservableDictionary<string, User> _users = null;

        //temp dictionry
        private MyObservableDictionary<string, User> _freshUsers = null;

        private int _selectedUserIndex;

        private DispatcherTimer _dispatcherTimer;


        public Account Account{ get; set;}

        public int SelectedUsersIndex
        {
            get { return _selectedUserIndex; }
            set
            {
                _selectedUserIndex = value;
                NotifyOfPropertyChange("SelectedUsersIndex");
            }
        }



        public MainViewModel()
        {
            _dispatcherTimer = new DispatcherTimer();
            _dispatcherTimer.Tick += DispatcherTimer_Tick;
            _dispatcherTimer.Interval = TimeSpan.FromSeconds(3);
            _dispatcherTimer.Start();
        }


        //I get every 3-4 sec from server new JSON data and I need update  with this data listbox in view
       private void DispatcherTimer_Tick(object sender, EventArgs eventArgs)
        {
            //server ping, call service method
            Account.Ping = _service.Ping(Account);

            //Refresh data in dictionary
            _freshUsers = _service.LoadUsers(Account);
            _users.Clear();
            SelectedUsersIndex = 1;

            foreach (var freshUser in _freshUsers)
            {
                _users.Add(freshUser);
            }

            //check if you have new messanges
            if (Account.Ping.Rp > 0)
            {
                //load new messanges
                for (int i = 0; i < Account.Ping.Rp; i++)
                {
                    #region load rp
                    try
                    {
                        Rp message = _service.LoadRp(Account);

                        if (message != null)
                        {
                            //show messages
                        }
                    }
                    catch (Exception exception)
                    {
                        if (exception.Message == "You haven&#8217;t any messanged")
                        {

                        }
                        throw exception;// how handle show this exception in view?
                    }
                    #endregion
                }
            }
        }
    }
like image 668
Gunter Avatar asked Dec 20 '10 19:12

Gunter


1 Answers

The DispatcherTimer is running on your UI thread so while it is running your check your UI will probably freeze while the DispatcherTimer_Tick message runs. If the DispatcherTimer_Tick takes 2 seconds to run then every 3 seconds you freeze the UI for 2 seconds. Users won't like that.

All service calls should be done on a non-UI thread so that you don't lock up the UI so I'd suggest using a timer and doing something like this:

public MainViewModel() 
{ 
   _stTimer = new System.Threading.Timer(Timer_Tick,null,3000,3000); 
   _dispatcher = Dispatcher.CurrentDispatcher;
} 

private void Timer_Tick(object sender)
{
   Account.Ping = _service.Ping(Account); 
   //Refresh data in dictionary 
   _freshUsers = _service.LoadUsers(Account); 
   _users.Clear(); 
   SelectedUsersIndex = 1; 

   foreach (var freshUser in _freshUsers) 
   { 
      _users.Add(freshUser); 
   } 

   for(int i=0;i<Account.Ping.Rp; i++)
   {
       //check if you have new messanges 
       if (Account.Ping.Rp > 0) 
       { 
           Rp message = _service.LoadRp(Account); 
           _messages.Add(message);
       } 
    }

    _dispatcher.BeginInvoke((Action)(()=>{OnPropertyChanged("Messages");}));
}

Here we're using a system timer to check for changes on a different thread, so your UI will be unaffected by any processing. When we want to notify the UI that a change has occured we can use the _dispatcher (the UI dispatcher we create in the constructor) to "BeginInvoke" a method on the UI thread.

This will make your app appear faster. A good rule of thumb is to keep off the Dispatcher thread as much as possible; only use it when you're doing something with the UI. All other processing should be on a background thread.

Hope this helps

like image 184
Faster Solutions Avatar answered Oct 16 '22 20:10

Faster Solutions