Таймер в виде модели - PullRequest
       27

Таймер в виде модели

5 голосов
/ 20 декабря 2010

У меня есть класс обслуживания во внешней сборке, я внедряю этот класс в класс модели представления с MEF. Мне нужно вызывать метод обслуживания каждые 3-4 секунды от модели представления.

Я получаю из сервиса новые данные в виде словаря. Этот словарь привязан к списку в поле зрения. И мне нужно обновить это окно со списком данных.

В своем решении я использую DispatcherTimer, но я абсолютный новичок в calibur. Я не знаю, что является подходящим решением в моем случае. Так что, если у кого-то есть успех, я буду благодарен.

Мое решение здесь:

[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
                }
            }
        }
    }

1 Ответ

7 голосов
/ 03 октября 2011

DispatcherTimer работает в вашем потоке пользовательского интерфейса, поэтому во время его проверки ваш пользовательский интерфейс, вероятно, зависнет, пока работает сообщение DispatcherTimer_Tick .Если для DispatcherTimer_Tick требуется 2 секунды, то каждые 3 секунды пользователь останавливает интерфейс на 2 секунды.Это не понравится пользователям.

Все сервисные вызовы должны выполняться в потоке, не связанном с пользовательским интерфейсом, чтобы не блокировать пользовательский интерфейс, поэтому я бы предложил использовать таймер и сделать что-то вроде этого:

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

Здесь мы используем системный таймер для проверки изменений в другом потоке, поэтому ваш пользовательский интерфейс не будет затронут любой обработкой.Когда мы хотим уведомить пользовательский интерфейс о том, что произошли изменения, мы можем использовать _dispatcher (диспетчер пользовательского интерфейса, который мы создаем в конструкторе) для «BeginInvoke» метода в потоке пользовательского интерфейса.

Это заставит ваше приложение появитьсяБыстрее.Хорошее эмпирическое правило - как можно больше избегать потока Dispatcher;используйте его только тогда, когда вы что-то делаете с пользовательским интерфейсом.Вся остальная обработка должна выполняться в фоновом потоке.

Надеюсь, это поможет

...