Timer in view model

I have a service class in an external assembly, I insert this class into a model model class with MEF. I need a call method every 3-4 seconds from the view model.

I get new service data like a Dictionary. This dictionary is tied to a list. And I need to update this data list.

In my solution, I use DispatcherTimer, but I am absolutely convinced of calibur.micto also MVVM and WPF. I do not know what is the appropriate solution in my case. Therefore, if anyone has progress, I will be grateful.

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 } } } } 
+4
source share
1 answer

DispatcherTimer runs on your user interface thread, so when it launches your check, your user interface will probably freeze when the DispatcherTimer_Tick message is executed. If it takes 2 seconds for DispatcherTimer_Tick and every 3 seconds you freeze the user interface for 2 seconds. Users will not like it.

All service calls should be made in a thread other than the UI so that you do not block the user interface, so I 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 use the system timer to check for changes in another thread, so your user interface will not be affected by any processing. When we want to notify the user interface that a change has occurred, we can use _dispatcher (the user interface manager that we create in the constructor) for the "BeginInvoke" method in the user interface thread.

This will make your application faster. A good rule of thumb is to disable the Dispatcher thread as much as possible; use it only when you are doing something with the user interface. All other processing should be in the background thread.

Hope this helps

+6
source

Source: https://habr.com/ru/post/1332813/