2010-12-20 49 views
4

我在外部程序集中有服务类,我在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 
       } 
      } 
     } 
    } 

回答

6

DispatcherTimer是在你的UI线程运行,所以当它运行你的支票,而DispatcherTimer_Tick消息运行你的用户界面可能会冻结。如果DispatcherTimer_Tick需要2秒运行,则每3秒钟冻结UI 2秒。用户不会喜欢那样。

所有服务调用应在非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进行操作时才使用它。所有其他处理应该在后台线程上。

希望这会有所帮助