none
Problem mit Datenaktualisierung (MVVM) in WPF RRS feed

  • Frage

  • Hi an alle Leser,

    ich habe arbeite an einem größerem Projekt, welches diverse Daten aus einer Datenbank lädt und diese lokal in MVVM-Klassen speichert. Bei Änderungen werden diese lokal und in der Datenbank eingepflegt, allerdings muss ich ja auch nach fremden Änderungen in der Datenbank suchen. Aus diesem Grund hatte ich erst einen Thread und später einen Timer verwendet.

    Ersteres brach direkt wieder ab, der Timer bekam eine Fehlermeldung, welche im Endeffekt darauf verwies, dass die UI nicht durch einen UI-Fremden Thread verändert werden dürfe.

    Ich gehe davon aus, dass der Thread indem die Änderungen durchgeführt werden ach direkt die entsprechenden Controls mit den Daten aktualisieren will, was natürlich zu dem Problem mit einem UI-Fremden Thread führt.

            public async Task Refresh()
            {
                try
                {
                    this.IsLoading = true;
    
                    App.DatabaseData = Database.Open(App.DatabaseSqlConnectionString);
    
                    App.DatabaseSql = "SELECT * FROM TextCodes ORDER BY Code";
                    App.DatabaseResults = App.DatabaseData.Query(App.DatabaseSql);
    
                    App.DatabaseData.Close();
    
                    this.TextEntries.Clear();
                    foreach (var dataRow in App.DatabaseResults)
                        this.TextEntries.Add(new TextEntriesDataModel()
                        {
                            ID = Guid.Parse(Convert.ToString(dataRow.ID)),
                            Code = Convert.ToString(dataRow.Code),
                            Text = Convert.ToString(dataRow.Text)
                        });
    
                    this.PropertyChanged((object)this, new PropertyChangedEventArgs("TextEntries"));
                    this.IsLoading = false;
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, "TextEntriesDataViewModel.cs");
                }
            }

    Das ist die Funktion, die einmal beim Start (in einem SplashScreen) und dann alle paar Minuten über einem Timer ausgeführt wird. So sehen auch die anderen Klassen aus, welche Daten laden.

    Meine Frage lautet nun: Wie kann ich die Daten Zeitgesteuert aktualisieren, ohne dass die Anwendung abstürzt und die UI nicht einfriert?

    Sonntag, 26. Oktober 2014 12:46

Antworten

  • Hallo,

    das async alleine bewirkt gar nichts, solange Du nicht auf etwas wartest (await).

    Das größere Problem bei Deinem Entwurf ist jedoch, dass er auf Singletons basiert wie DatabaseData. Damit ist es kaum möglich, mehrere Threads unabhängig arbeiten zu lassen, ohne dass sie sich in die Quere kommen. Damit die Datenabfragen asynchron laufen können, solltest Du jeweils Instanzen einer Klasse erzeugen, die wenig bis gar keine gemeinsame veränderlichen Daten teilen. Für Datenbankzugriffe hieße das, eigene Verbindungen zu verwenden und als Rückgabe eine neue Instanz (hier DataTable) zu erzeugen.

    Dann kannst Du den Zugriff via await GetDatabaseResults auf einen Hintergrund-Thread legen.

    Das Aktualisieren der gebundenen Daten muss zwar auf dem Vordergrund-Thread laufen, da Standard-Auflistungen wie ObservableCollection nicht thread-safe sind. Du könntest jedoch das Volumen der Aktualisierung reduzieren - und damit die Zahl der Benachrichtigungen -, in dem Du zuerst ermittelst, welche Einträge sich effektiv geändert haben - i. d. R. sind das nur (sehr) wenige.

    Gruß Elmar

    Sonntag, 26. Oktober 2014 16:31