2016-10-05 6 views
2

Ich schreibe eine Anwendung in C#/WPF/Entity Framework DB zuerst kommuniziert mit einem proprietären Stück der industriellen Hardware, die Werte wie Durchfluss und Temperatur von einer Kühlmittelleitung misst. Diese Werte werden häufig in meiner SQL Server-Datenbank mit einem Thread aktualisiert, der im Hintergrund ausgeführt wird und dann in meiner Benutzeroberfläche angezeigt wird.So aktualisieren Sie WPF UI als Datenbankänderungen

Mein Anliegen ist derzeit, wie ich meine Benutzeroberfläche aktualisieren, um diese Änderungen widerzuspiegeln. Hier ist ein Beispiel dafür, wie ich einen Datagrid aktualisieren:

ich meine Datacontext zu meinem Viewmodel gesetzt und einen Thread instanziiert, dass jede Sekunde läuft:

_DataContext = new ViewModels.SummaryTable_ViewModel(); 
    this.DataContext = _DataContext; 
    UIUpdateThread = new Thread(UIUpdaterThread); 
    UIUpdateThread.IsBackground = true; 
    UIUpdateThread.Start();  

Das Modell meines Raster auf basiert ist ein IList <> das sieht wie folgt aus:

private IList<channel> _channel; 
    public IList<channel> Channels 
    { 
     get 
     { 
      return _channel; 
     } 
     set 
     { 
      _channel = value; 
      //NotifyPropertyChanged(); 
      OnPropertyChanged("Channels"); 
     } 
    } 

dann jede Sekunde meine UIUpdateThread meine FillChannels nennt() -Methode, die sich wie folgt, dann werden die Gitter-Updates auf dem Property Benachrichtigung basiert:

using (var DTE = new myEntities()) 
      { 
       if (DTE.channels.Any()) 
       { 
        var q = (from a in DTE.channels 
          where a.setup.CurrentSetup == true 
          orderby a.ChannelNumber 
          select a).ToList(); 

        this.Channels = q; 
       } 
      } 

Also meine Frage ist das: gibt es eine bessere, elegantere Möglichkeit, dies zu tun? Das fühlt sich "falsch" an, weil es keinen besseren Begriff gibt. Und es hat schlechte Nebeneffekte, wie das Zurücksetzen der benutzerdefinierten Sortierung auf meinem Datagrid jedes Mal, wenn der Thread ausgeführt wird. Außerdem denke ich, dass es das MVVM-Muster bricht, obwohl ich nicht sicher bin. Ich denke zum Beispiel, was passiert, wenn der Thread, der mit meiner Hardware redet, jedes Mal ein gemeinsam genutztes Channel-Objekt aktualisiert, wenn er die Hardware nach Daten abfragt, und ich einfach meine UIs daran anbinde, würde ich das nicht tun müssen Führen Sie diesen Thread (oder die anderen Threads auf meinen anderen UIs, die dasselbe tun) nur auf Basis von PropertyChanged-Benachrichtigungen aus. Oder gibt es eine andere Methode, die mir völlig unbekannt ist? Bei der Suche nach einer Antwort habe ich erwähnt, dass das Muster der Arbeitseinheit, mit dem ich nicht vertraut bin, ein relevantes Konzept ist.

Wie Sie sehen können, bin ich mir nicht sicher, wohin ich von hier aus gehen könnte und könnte wirklich Hilfe gebrauchen. Entschuldigung für die Textwand, ich wollte nur so gründlich wie möglich sein. Jede Hilfe würde sehr geschätzt werden. Vielen Dank.

+1

Ich würde 'Channels' eine' ObservableCollection' machen, um damit zu beginnen. Wenn Elemente hinzugefügt oder entfernt werden, würde ich sie hinzufügen/entfernen, anstatt die Sammlung neu zu erstellen. Im Allgemeinen ist Ihr vorletzter Absatz auf dem Geld: Ändern Sie vorhandene Dinge, die entsprechende Änderungsbenachrichtigungen auslösen. Wird relativ verwirrt, wenn man den gesamten neuen aktuellen Zustand plumpst, aber wenn Sie das tun müssen, müssen Sie das tun. P.S .: Was Rory.ap gesagt hat. –

+0

Danke für die Hilfe @EdPlunkett – user3900520

Antwort

4

Ich denke, Ihr Modell sollte derjenige sein, der Ihr Ansichtsmodell benachrichtigt, wenn neue Daten vorhanden sind. Sie sollten jeden Mechanismus, der dies bewirkt (wie der Timer, den ich vermute, dass Sie verwenden) in das Modell einfügen.

Grundsätzlich benachrichtigt Ihr Modell Ihr Ansichtsmodell und Ihr Ansichtsmodell benachrichtigt die Ansicht, dass Datenänderungen vorliegen. Wenn Sie Ihre Sicht richtig einrichten und XAML statt Code-Behinds verwenden, sollte alles automatisch über die Datenbindungen zwischen der Ansicht und dem Ansichtsmodell zusammengeführt werden.

In Bezug auf Sortierung: Dies sollte eine separate Eigenschaft Ihres Ansichtsmodells sein, die an die Sortiereigenschaft im Raster Ihrer Ansicht gebunden ist. Ihr Modell sollte die vom Benutzer festgelegte Sortierung beibehalten und sie entsprechend auf die aktualisierten Daten anwenden, bevor das Ansichtsmodell benachrichtigt wird, wenn Daten geändert werden.

Ich bin mir nicht sicher, ob die Einheit der Arbeit hier anwendbar ist, da Sie nicht über das Fortbestehen verwandter Datenreihen zu mehreren Tabellen sprechen und dies als eine Transaktion tun - Sie lesen nur Daten. Ich könnte mich jedoch irren, da ich die Arbeitseinheit nicht so oft studiert habe.


Um Ihre Fragen in den Kommentaren Adresse:

Lassen Sie uns einen Schritt zurück. Ihr Ansichtsmodell sollte nur sich mit Logik befassen, die sich auf die Darstellung der zugehörigen Ansicht bezieht. Es sollte keinen Datenzugriffscode oder -code enthalten, der Geschäftslogik oder domänenbezogene Aufgaben ausführt. Dieser Code geht in das zusammen, was man "Modell" nennt (vergib mir, wenn du das schon hast, aber es ist schwer zu sagen, wo genau der Code liegt, den du in deiner Frage angegeben hast).

Das Modell kann aus einer Reihe von Klassen bestehen, die verschiedene Geschäftslogikaufgaben ausführen oder die Ihre Domänen-/Entitäts-POCOs darstellen (wie Ihre Entitäts-Framework-generierten Klassen).

Ich bin ein wenig unklar, was Ihr Channel-Objekt ist und wie es von Ihrer Entity-Klasse/POCO, d. H. Das EF-generierte Modell getrennt ist. Aber wiederum sollten Ihre Interaktion mit EF und die Wartung und Logik in Bezug auf Ihre Entitäten im Modell geschehen.

Also, die Idee wäre, dass Sie nach Datenänderungen im Modell suchen, mit welchem ​​Mechanismus Sie auch wollen - z. ein Timer (übrigens gibt es Timer, die synchron laufen, also verschmelze nicht den Begriff "Timer" mit "thread") oder binden direkt an das Ereignis "collection changed" in deiner Sammlung von Entitäten. Wenn eine Änderung erkannt wird, würden Sie einfach die für diese Änderung im Modell erforderliche Geschäftslogik (z. B. das Anwenden von Transformationen, Sortierung, Protokollierung usw.) ausführen und dann dem Ansichtsmodell mitteilen, dass die Änderung eingetreten ist.

+0

Ok. Zunächst einmal danke für die Hilfe. Um zu sehen, ob ich richtig verstehe - was ist mein Modell in diesem Fall? Sind es die automatisch generierten Modelle von Entity Framework? Wenn ja, muss ich CodeFirst konvertieren, damit ich sie ändern kann? Oder ist es das Kanalobjekt, das ich in meinem Viewmodel habe? Ist die Idee, dass ich einen Thread in das Modell setzen würde, das die Datenbank ab und zu abfragt, wie ich es jetzt mache, und binde direkt daran? Dann werden meine Benutzeroberflächen aktualisiert, weil das CollectionChanged-Ereignis ausgelöst wird? (Ich nehme an, das ist die, die ich brauche, weil meine Sammlung mehr bearbeitet als hinzugefügt/entfernt wurde – user3900520

+0

Ich hasse es dich zu ärgern, @ rory.ap - Ich habe meine Frage in dem obigen Kommentar bearbeitet. Könnte nur ein kleines bisschen Klärung verwenden wo ich mein Modell auf den neuesten Stand bringen muss/was wir mit dem Modell meinen, ich glaube, ich bin sehr nah daran, das zu verstehen, ging voraus und markierte deine Antwort als akzeptiert, weil es die einzige Antwort war und zu decken scheint, was ich Ich muss nur wissen, ich bin nur noch ein wenig verwirrt wegen meiner mangelnden Erfahrung. Egal, danke nochmal. – user3900520

+1

@ user3900520 - Kein Problem. Siehe mein Update. –