EntityFramework und ObservableCollection
-
Hallo.
Ich würde gerne eine Tabelle aus der DB die ich über das EntityFramework (Model First) lade in meiner Oberfläche (WPF) anzeigen und bearbeiten.
Das Problem ist das die erzeugte Liste vom Typ ICollection ist und nicht vom Typ ObservableCollection. Füge ich der Liste was hinzu oder lösche ich einen Eintrag wird dies nicht in der Oberfläche aktualisiert.
Zunächst hatte ich die Idee die Daten auszulesen und im ViewModel in eine ObservableCollection zu laden. Und hierauf dann die Änderungen durchzuführen.
Das Problem ist hier diese Liste nach Änderung mit der Datenbank wieder abzugleichen. (Prüfen welches Objekt ist hizugekommen, welches wurde gelöscht)
Gibt es hier bessere und einfachere Lösungen?
-
public static ObservableCollection<T> ToObservableCollection<T>(this IEnumerable<T> enumeration) { return new ObservableCollection<T>(enumeration); }
-
Sorry, nicht ganz durchgelesen.
Dein Problem ist also auf Änderungen in der Datenbank zu reagieren?
-
Hallo
Nein. Klar ist wie ich von der ICollection eine ObservableCollection erhalte.
Auch möchte ich nicht über Änderungen in der DB informiert werden.Also Beispiel:
Daten in der DB
Item1
Item2
Item3
Item4werden in eine ObservableCollection geladen. Daten sind in beiden Listen synchron.
Nun lösche ich in der OC Item1 und Item2 und füge Item5 hinzu. OC und die ICollection sind nicht mehr synchron
Wenn ich das ganze nun zurück in die Datenbank speichern will muss ich die Daten aus der OC zurück in die ICollection schieben.
Hier habe ich nun folgende Möglichkeiten.
1.Entweder vergleiche ich Objekt für Objekt ob ich es zur ICollection hinzufügen muss oder auch entfernen muss. Danach führe ich einen Commit in die DB durch.
Vorteil: Ich muss nur in die DB speichern wenn die Liste auch wirklich geändert wurde
Nachteil: Ich muss jedes einzelne Objekt prüfen2. Ich nehme ersetze die Daten ICollection komplett mit den Daten der OC.
Vorteil: Ich muss nicht Objekt für Objekt prüfen.
Nachteil: Es wird immer in die DB gespeichert. Ob es Änderungen gibt oder nicht3. ... Hier könnte eine Lösung von euch stehen
-
administratorin schrieb:
3. ... Hier könnte eine Lösung von euch stehen
3. Du hängst dich als Observer auf die OC drauf, und änderst alles was in der OC geändert wird auch in der ICollection.
Könnte aber u.U. deutlich mehr Aufwand sein als Möglichkeit 1.1. dagegen sollte sich sogar generisch implementieren lassen, so dass man es auch für andere Item Typen verwenden kann. Vorausgesetzt die Items haben keine "nicht-property" Felder und implementieren alle korrekt INotifyPropertyChanged.
ps: OK, ... 3. sollte sich auch generisch implementieren lassen
Der Nachteil ist aber dass du bei 3. die ICollection änderst während die OC geändert wird - also u.U. zu früh. Liesse sich aber dadurch entschärfen dass du die ICollection kopierst (deep), und dann diese Kopie änderst.
-
Hm.
Angesicht dessen macht Lösung 2 vieleicht doch Sinn. Zumal es sich um eine Tabelle handelt die nicht mehr als 50 Einträge hat und selten geändert wird.
Und noch ne weitere Lösung:
4. Ich ändere das T4 Template und generiere eine ObservableCollection statt einer ICollection.
Was meint ihr dazu?
-
Vielleicht passt das für Deinen Anwendungsfall:
Minimiertes Beispiel:
<Window x:Class="TestDialog" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Testat" WindowStartupLocation="CenterScreen" Height="407" Width="654" Name="windowSelect" Loaded="Window_Loaded" ResizeMode="NoResize"> <Window.CommandBindings> <CommandBinding x:Name="NewCommand" Command="ApplicationCommands.New" Executed="NewCommand_Executed" CanExecute="NewCommand_CanExecute"/> <CommandBinding x:Name="DeleteCommand" Command="ApplicationCommands.Delete" Executed="DeleteCommand_Executed" CanExecute="DeleteCommand_CanExecute"/> </Window.CommandBindings> <Grid> <DataGrid AutoGenerateColumns="False" Margin="10,9,9,41" Name="DataGridTest" ItemsSource="{Binding}"> <DataGrid.Columns> <DataGridTextColumn Header="Bezeichnung" Binding="{Binding Path=Bezeichnung}" Width="*" /> </DataGrid.Columns> </DataGrid> </Grid> </Window>
Beachten das als ItemSource {Binding} angegeben wird. Sonst funktioniert das nicht
Dann im CodeBehind:
public partial class TestDialog : Window { private MyDataContext DbContext = new MyDataContext; public TestDialog() { InitializeComponent(); } private void Window_Loaded(object sender, RoutedEventArgs e) { DataGridTest.DataContext = DbContext.TabellenName; } private void DataGridTest_CurrentCellChanged(object sender, EventArgs e) { DbContext.SubmitChanges(); } }
Als Datacontext kann auch eine Linq-Statement gesetzt werden, z.B.:
DataGridTest.DataContext = DbContext.TabellenName.Where(a => a.Purpose == false) DataGridTest.DataContext = DbContext.TabellenName.OrderBy(a => a.Name)
-
Sorry sendro . Aber ich glaube du hast nicht verstanden was hier das Thema ist.