|
VB.Net-Forum - Beitragsübersicht - |
|
Thema | V03: Komplexes Problem: Casting oder DataGrid |
Von |
Stan |
Datum |
23. Februar 2016 um 22:53:31 |
Frage |
Hallo zusammen,
ich habe noch ein Thema bei dem ich einen Sparringspartner brauche.
Ich habe ein DataGrid, dass ich direkt an eine ObservableCollection gebunden habe. Die Collection ist von meinem Basistyp, sagen wir zur Vereinfachung, diese wäre vom Typ Fahrzeug. Nun gibt es mehrere Ableitungen wie z.B. Auto oder Flugzeug.
Meine Idee war, dass der User im Datagrid alle Fahrzeuge(Auto, Flugzeug, etc) sehen und bearbeiten kann. Anfäglich kann der User nur die Eigenschaften verändern, die alle gemeinsam besitzen, also Fahrzeug. Setzt der User einen Filter, beidem nur noch Autos übrg bleiben, so würde ich die ObservableCollection Casten und darauß Autos machen. Der User könnte sofort alle Eigenschaften eines Autos bearbeiten. Hochdynamisch ;-)
Mein Problem ist das Anlegen einer neuen Zeile. Der User sollte die Art des Fahrzeugs über eine Dropdownliste auswählen können. Allerdings wird durch das DataGrid bereits beim Anklicken der neuen Zeile ein neues Objekt angelegt, dann vom Basistyp.
Zuerst wollte ich das Anlegen der neuen Zeile bis zur Auswahl des Typs via Combobox heruaszögern, aber ich glaube das DataGrid braucht den Eintrag zur Datenhaltung. => Hier bin aber offen für Lösungsvorschläge
Deshalb habe ich mich auf das Casten konzentriert, um die Objekte im Nachgang zu verändern. Ich weiß, dass ich => aus einem Child immer den Parent casten kann(Auto => Fahrzeug) => den so erstellen Parent wieder zum Child casten kann(Fahrzeug(Auto) => Auto)
Allerdings müsste ich ein reinen Parent zu einem beliebigen Child(Fahrzeug => Auto) "erweitern", beziehungsweise ein Child in ein anderes Child(Auto => Flugzeug) "umwandeln" können. Ich würde einen Datenverlust aller Childvariablen akzeptieren.
Irgendwelche Ideen?
Beste Grüße StanPublic Class Fahrzeug Public geschwindigkeit As Integer End Class Public Class Auto Inherits Fahrzeug Public Allrad As Boolean End Class Public Class Flugzeug Inherits Fahrzeug Public maxFlughoehe As Long End Class |
|
Antwort: |
Von |
Nico |
E-Mail |
nico.schertler@studentpartners.de |
Datum |
03. März 2016 um 10:41:00 |
Antwort |
Hallo,
ich hatte an so etwas in der Art gedacht:'XAML: <DataGrid Name="dg" AutoGenerateColumns="True"/> 'Code Behind: Imports System.Collections.ObjectModel Imports System.Collections.Specialized Class MainWindow Dim transportMittel As New ObservableCollection(Of Transportmittel) Private Sub Window_Loaded(sender As Object, e As RoutedEventArgs) dg.ItemsSource = New ObservableCollectionView(Of Transportmittel, Auto)(transportMittel) transportMittel.Add(New Auto With {.Id = 0, .Marke = "Audi"}) transportMittel.Add(New Flugzeug With {.Id = 1, .Hersteller = "Boeing"}) transportMittel.Add(New Auto With {.Id = 2, .Marke = "BMW"}) End Sub End Class MustInherit Class Transportmittel Public Property Id As Integer End Class Class Auto : Inherits Transportmittel Public Property Marke As String End Class Class Flugzeug : Inherits Transportmittel Public Property Hersteller As String End Class Public Class ObservableCollectionView(Of TBasis, TFilter As TBasis) Implements ICollection(Of TFilter) Implements INotifyCollectionChanged Dim datenQuelle As ObservableCollection(Of TBasis) Public Sub New(datenQuelle As ObservableCollection(Of TBasis)) Me.datenQuelle = datenQuelle AddHandler datenQuelle.CollectionChanged, AddressOf datenQuelle_CollectionChanged End Sub Public ReadOnly Property Count As Integer Implements ICollection(Of TFilter).Count Get Return datenQuelle.Count End Get End Property Public ReadOnly Property IsReadOnly As Boolean Implements ICollection(Of TFilter).IsReadOnly Get Return CType(datenQuelle, ICollection(Of TBasis)).IsReadOnly End Get End Property Public Event CollectionChanged As NotifyCollectionChangedEventHandler Implements INotifyCollectionChanged.CollectionChanged Private Sub datenQuelle_CollectionChanged(sender As Object, e As NotifyCollectionChangedEventArgs) If e.Action = NotifyCollectionChangedAction.Add Then Dim tatsächlicheNeueElemente As New List(Of TFilter) For Each item As TBasis In e.NewItems If TypeOf item Is TFilter Then tatsächlicheNeueElemente.Add(item) Next If e.NewItems.Count > 0 Then Dim args As New NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, tatsächlicheNeueElemente) RaiseEvent CollectionChanged(Me, args) End If End If 'Weitere Aktionen implementieren End Sub Public Sub Add(item As TFilter) Implements ICollection(Of TFilter).Add datenQuelle.Add(item) End Sub Public Sub Clear() Implements ICollection(Of TFilter).Clear datenQuelle.Clear() End Sub Public Sub CopyTo(array() As TFilter, arrayIndex As Integer) Implements ICollection(Of TFilter).CopyTo Throw New NotImplementedException() End Sub Public Function Contains(item As TFilter) As Boolean Implements ICollection(Of TFilter).Contains Return datenQuelle.Contains(item) End Function Public Function Remove(item As TFilter) As Boolean Implements ICollection(Of TFilter).Remove Return datenQuelle.Remove(item) End Function Public Function GetEnumerator() As IEnumerator(Of TFilter) Implements IEnumerable(Of TFilter).GetEnumerator Return New ObservableCollectionViewEnumerator(Of TBasis, TFilter)(datenQuelle) End Function Private Function IEnumerable_GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator Return New ObservableCollectionViewEnumerator(Of TBasis, TFilter)(datenQuelle) End Function End Class Public Class ObservableCollectionViewEnumerator(Of TBasis, TFilter As TBasis) Implements IEnumerator Implements IEnumerator(Of TFilter) Dim baseEnumerator As IEnumerator(Of TBasis) Public Sub New(datenQuelle As ObservableCollection(Of TBasis)) baseEnumerator = datenQuelle.GetEnumerator() SucheNächstesElementMitPassendemTyp() End Sub Private Function SucheNächstesElementMitPassendemTyp() As Boolean While Not TypeOf baseEnumerator.Current Is TFilter If Not baseEnumerator.MoveNext() Then Return False End While Return True End Function Public ReadOnly Property Current As Object Implements IEnumerator.Current Get Return baseEnumerator.Current End Get End Property Private ReadOnly Property IEnumerator_Current1 As TFilter Implements IEnumerator(Of TFilter).Current Get Return baseEnumerator.Current End Get End Property Public Sub Reset() Implements IEnumerator.Reset baseEnumerator.Reset() End Sub Public Function MoveNext() As Boolean Implements IEnumerator.MoveNext If Not baseEnumerator.MoveNext() Then Return False Return SucheNächstesElementMitPassendemTyp() End Function Public Sub Dispose() Implements IDisposable.Dispose baseEnumerator.Dispose() End Sub End Class Anstatt das DataGrid an die ObservableCollection zu binden, erstellst du ein ObservableCollectionView, die nur die Elemente mit dem entsprechenden Typ zurückgibt, und bindest es daran. Wichtig ist, dass in dieser Klasse die datenQuelle_CollectionChanged() richtig implementiert wird. Ich habe das jetzt nur für die Add-Aktion gemacht. Im Beispiel wird ein View erstellt, der nur Autos aus der ObservableCollection herausfiltert. Durch diese starke Typisierung weiß das DataGrid dann auch, welche Spalten es anzeigen soll. Umgesetzt wird das durch die Implementierung von Implements ICollection(Of TFilter). |
|
[ Antwort schreiben | Zurück zum VB.Net-Forum | Forum-Hilfe ] |
|
Letzte Aktualisierung: Sonntag, 13. Dezember 2015 |
|