2010-12-20 51 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進行操作時才使用它。所有其他處理應該在後臺線程上。

希望這會有所幫助