2010-12-20 7 views
4

Ich habe Service-Klasse in externen Assembly, ich injiziere diese Klasse in Ansicht Modellklasse mit MEF. Ich brauche Call Service-Methode alle 3-4 Sekunden vom Ansichtsmodell.Timer in Ansicht Modell

Ich bekomme aus dem Dienst neue Daten als Dictionary. Dieses Wörterbuch ist an die Listenansicht gebunden. Und ich muss mit dieser Datenliste in Sicht aktualisieren.

In meiner Lösung verwende ich DispatcherTimer, aber ich bin absoluter Beginner in calibur.micto auch MVVM und WPF. Ich weiß nicht, was in meinem Fall eine geeignete Lösung ist. Also wenn jemand Vorschuss hat, werde ich dankbar sein. Meine Lösung

ist hier:

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

Antwort

6

Die DispatcherTimer auf dem UI-Thread ausgeführt wird, so, während es Ihre Überprüfung Ihrer Benutzeroberfläche läuft wahrscheinlich einfrieren, während die DispatcherTimer_Tick Nachricht läuft. Wenn der DispatcherTimer_Tick 2 Sekunden zum Ausführen benötigt, dann frieren Sie alle 3 Sekunden die Benutzeroberfläche für 2 Sekunden ein. Benutzer werden das nicht mögen.

Alle Service-Anrufe sollten auf einem Nicht-UI-Thread ausgeführt werden, so dass Sie die Benutzeroberfläche nicht sperren, so ich so einen Timer und etwas zu tun, würde vorschlagen, mit:

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

Hier wir Verwenden Sie einen Systemzeitgeber, um nach Änderungen in einem anderen Thread zu suchen, sodass Ihre Benutzeroberfläche von keiner Verarbeitung beeinträchtigt wird. Wenn wir die Benutzeroberfläche darüber informieren möchten, dass eine Änderung aufgetreten ist, können wir den _dispatcher (den UI-Dispatcher, den wir im Konstruktor erstellen) verwenden, um eine Methode im UI-Thread zu starten.

Dies wird Ihre App schneller erscheinen lassen. Eine gute Faustregel ist, den Dispatcher-Thread so weit wie möglich fernzuhalten. verwende es nur, wenn du etwas mit der Benutzeroberfläche machst. Alle anderen Verarbeitungen sollten in einem Hintergrundthread stattfinden.

Hoffe, das hilft