视图模型中的计时器

时间:2010-12-20 19:29:34

标签: c# timer viewmodel caliburn.micro

我在外部程序集中有服务类,我在MEF的视图模型类中注入了这个类。我需要从视图模型每3-4秒调用一次服务方法。

我从服务新数据获得字典。此词典在视图中绑定到列表框。我需要在视图中刷新此数据列表框。

在我的解决方案中,我使用DispatcherTimer,但我在calibur.micto中也是MVVM和WPF的绝对优势。在我的案例中,我不知道什么是合适的解决方案。所以,如果有人提前,我将感激不尽。

我的解决方案在这里:

[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 个答案:

答案 0 :(得分:7)

DispatcherTimer 正在您的UI线程上运行,因此当它运行您的检查时,您的UI可能会在 DispatcherTimer_Tick 消息运行时冻结。如果 DispatcherTimer_Tick 需要2秒才能运行,那么每隔3秒就会冻结UI 2秒钟。用户不会喜欢这样。

所有服务调用都应该在非UI线程上完成,这样你就不会锁定UI,所以我建议使用计时器并执行以下操作:

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

这里我们使用系统计时器来检查不同线程上的更改,因此您的UI将不受任何处理的影响。当我们想要通知UI发生了更改时,我们可以使用_dispatcher(我们在构造函数中创建的UI调度程序)在UI线程上“BeginInvoke”一个方法。

这会让您的应用显得更快。一个好的经验法则是尽可能地避开Dispatcher线程;只有在用UI做某事时才使用它。所有其他处理应该在后台线程上。

希望这有帮助