ICollectionView, ListBox, liste der Aktuell angezeigten Items

  • WPF

Es gibt 9 Antworten in diesem Thema. Der letzte Beitrag () ist von Nofear23m.

    ICollectionView, ListBox, liste der Aktuell angezeigten Items

    Hi @ all,

    ich bin mir nicht sicher ob das Problemchen zu 100 % WPF bezogen ist, daher bitte ich um verschiebung des Threads sollte es doch eher in allgemein gehören =)

    Kontext:
    Ich habe ein Programm in der mache, in welchem man schlicht Aufträge angeben kann, diese beeinhalten das Auftragsdatum, einen Kundennamen, den Brutto,Netto und MwSt- Wert des AUftrages.
    Die Aufträge werden in einer ObservableCollection eingetragen/angelegt. Durch eine ICollection(View) sind die Aufträge an eine Listbox gebunden, um mir das Filtern zu ermöglichen, das funktioniert soweit einwandfrei, meine Problematik ist nun jedoch,
    wenn ich z.B. ein UserControl verwenden möchte, welches mir die Addierten Werte für jedes aktuell angezeigte Item ausgeben soll.

    Nun endet bereits mein aktuelles Latein, mein momentaner Ansatz ist folgendes Property:

    VB.NET-Quellcode

    1. Private ReadOnly _combinedbrutto As Decimal
    2. Public ReadOnly Property CombinedBrutto() As Decimal
    3. Get
    4. Dim tmpDec As Decimal = 0
    5. For Each it As AuftragModel In ListView.Items ' hier auch unsauber an die ListBox(Name ListView) gehängt, da muss es doch sicherlich eine Möglichkeit über Binding geben
    6. tmpDec = tmpDec + it.BruttoPreis
    7. Next
    8. Return tmpDec
    9. End Get
    10. End Property


    nun müsste ich aber leider bei jeder Aktion (Filtereingabe usw.) mit

    VB.NET-Quellcode

    1. RaisePropertyChanged("CombinedBrutto")
    dafür sorgen das mein Window wind von der änderung bekommt. Ich vermute mal das ich hier den Wald vor lauter Bäumen nicht sehe, bzw. das mein Ansatz womöglich schwachsinn ist.

    Kann mir evtl. jemand einen Denkanstoss geben wie ich:

    Ein Property an die aktuell angezeigten Items meiner Listbox binden kann, so das ich je nach den angezeigten Items, wiederum Werte der Items addieren und diese in einem Extra Usercontrol anzeigen kann.


    Wenn mehr Code gewünscht ist, kann ich den gerna noch anhängen, aber da es mir scheint hier um ein Grundlegendes Gedanken -und weniger ein Codeproblem geht, hab ich erstmal nur die Theorie gepostet.


    Lg und Danke
    If Energy = Low Then
    Drink(aHugeCoffee)
    Else
    Drink(aHugeCoffeeToo)
    End If
    Hallo Asus

    asusdk schrieb:

    welches mir die Addierten Werte für jedes aktuell angezeigte Item ausgeben soll.

    Da hänge ich leider. Welche Werte willst du Addieren? Du hast doch alle Werte als Properties wie du schreibst. Brutton, Netto, und MwSt.

    Hoffentlich sind entweder Brutton oder Netto als ReadOnly Properties implementiert aber das ist ein anderes Thema.

    Wenn du meinst das du die SUMME von Werten haben willst geht das mit LINQ wunderbar. Um dir ein Beispiel erstellen zu können benötigen wir aber die ViewModel Klasse, die Model Klasse und wenn möglich eine klare belastbare Aufgabenstellung.

    Dann kann ich dir sicher besser und für die nachvollziehbar helfen.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Da hänge ich leider. Welche Werte willst du Addieren? Du hast doch alle Werte als Properties wie du schreibst. Brutton, Netto, und MwSt.


    Also auf dem Window ist eine ListBox, diese zeigt die gefilterten Items aus der ObservableCollections an. Ein weiteres UserControl auf dem selben Fenster soll, quasi immer die Zusammengezählten Werte, der aktuell angezeigten Items anzeigen.

    10 Items zu je 20 € Brutto in der Listbox <-> Ein Label mit 200 € Brutto in dem Usercontrol.

    Ich scheitere aktuell daran, wie dies automatisch per Binding von statten gehen könnte, da ich ja entweder so etwas wie ListBox.Count(Property) bräuchte (was allerdings nicht auf änderungen an den items selbst reagieren würde) oder alternativ ein (wenn auch eher ungern) Event welches Feuert, sobald die Itemanzahl (besser noch auch der ItemInhalt selbst) verändert wurden, so das ich dann die jeweiligen Propertys wie z.B. CombinedBrutto entsprechend aktualisieren kann, da diese ja auf die Labels in besagten zweiten UCL gebunden sind.

    Denke ich hier evtl. in die verkehrte Richtung ?

    p.S. eine ViewModelKlasse gibt es nicht im direkten Sinne, mein "ViewModel" ist der Codebehind des Window
    MainWindow:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.Collections.ObjectModel
    2. Imports System.Collections.Specialized
    3. Imports System.ComponentModel
    4. Imports System.Runtime.CompilerServices
    5. Class MainWindow
    6. Implements INotifyPropertyChanged
    7. Public Sub New()
    8. InitializeComponent()
    9. CreateSampleAuftraege()
    10. AuftragsListeView = CollectionViewSource.GetDefaultView(Auftraege)
    11. AuftragsListeView.Filter = AddressOf ViewFilter
    12. End Sub
    13. #Region "Propertys"
    14. Private _auftraege As New ObservableCollection(Of AuftragModel)
    15. Public Property Auftraege() As ObservableCollection(Of AuftragModel)
    16. Get
    17. Return _auftraege
    18. End Get
    19. Set(ByVal value As ObservableCollection(Of AuftragModel))
    20. _auftraege = value
    21. End Set
    22. End Property
    23. Private _listboxselectedItem As AuftragModel
    24. Public Property ListBoxSelectedItem() As AuftragModel
    25. Get
    26. Return _listboxselectedItem
    27. End Get
    28. Set(ByVal value As AuftragModel)
    29. _listboxselectedItem = value
    30. End Set
    31. End Property
    32. Private ReadOnly _combinedbrutto As Decimal
    33. Public ReadOnly Property CombinedBrutto() As Decimal
    34. Get
    35. Dim tmpDec As Decimal = 0
    36. For Each it As AuftragModel In ListView.Items
    37. tmpDec = tmpDec + it.BruttoPreis
    38. Next
    39. Return tmpDec
    40. End Get
    41. End Property
    42. #End Region
    43. #Region "CollectionView and Filter"
    44. Private _auftragslisteview As ICollectionView
    45. Public Property AuftragsListeView() As ICollectionView
    46. Get
    47. Return _auftragslisteview
    48. End Get
    49. Set(ByVal value As ICollectionView)
    50. _auftragslisteview = value
    51. RaisePropertyChanged()
    52. End Set
    53. End Property
    54. Private Function ViewFilter(obj As Object) As Boolean
    55. Dim Startdate As DateTime? = Now
    56. Dim Enddate As DateTime? = Now
    57. If FilterStartdate Is Nothing Then
    58. Startdate = Date.MinValue.AddDays(1)
    59. Else
    60. Startdate = FilterStartdate
    61. End If
    62. If FilterEndDate Is Nothing Then
    63. Enddate = Date.MaxValue.AddDays(-1)
    64. Else
    65. Enddate = CType(FilterEndDate, DateTime).AddDays(1)
    66. End If
    67. Dim currentAuftrag As AuftragModel = CType(obj, AuftragModel)
    68. If String.IsNullOrEmpty(FilterText) Then
    69. Return CBool(currentAuftrag.AuftragsDatum >= Startdate AndAlso currentAuftrag.AuftragsDatum <= Enddate)
    70. Else
    71. Return CBool(currentAuftrag.AuftragsDatum >= Startdate AndAlso currentAuftrag.AuftragsDatum <= Enddate AndAlso currentAuftrag.KundenName.ToLower.Contains(FilterText.ToLower))
    72. End If
    73. End Function
    74. Private _filterText As String
    75. Public Property FilterText() As String
    76. Get
    77. Return _filterText
    78. End Get
    79. Set(ByVal value As String)
    80. _filterText = value
    81. AuftragsListeView.Refresh()
    82. ' RaisePropertyChanged("CombinedBrutto")
    83. RaisePropertyChanged()
    84. End Set
    85. End Property
    86. Private _filterstartdate As DateTime?
    87. Public Property FilterStartdate() As DateTime?
    88. Get
    89. Return _filterstartdate
    90. End Get
    91. Set(ByVal value As DateTime?)
    92. _filterstartdate = value
    93. AuftragsListeView.Refresh()
    94. ' RaisePropertyChanged("CombinedBrutto")
    95. RaisePropertyChanged()
    96. End Set
    97. End Property
    98. Private _filterenddate As DateTime?
    99. Public Property FilterEndDate() As DateTime?
    100. Get
    101. Return _filterenddate
    102. End Get
    103. Set(ByVal value As DateTime?)
    104. _filterenddate = value
    105. AuftragsListeView.Refresh()
    106. ' RaisePropertyChanged("CombinedBrutto")
    107. RaisePropertyChanged()
    108. End Set
    109. End Property
    110. #End Region
    111. #Region "Commands"
    112. Private _resetfiltercommand As ICommand
    113. Public Property ResetFilterCommand() As ICommand
    114. Get
    115. If _resetfiltercommand Is Nothing Then
    116. _resetfiltercommand = New Helper.RelayCommand(AddressOf ResetFilterCommand_Execute, AddressOf ResetFilterCommand_CanExecute)
    117. End If
    118. Return _resetfiltercommand
    119. End Get
    120. Set(ByVal value As ICommand)
    121. _resetfiltercommand = value
    122. End Set
    123. End Property
    124. Private Function ResetFilterCommand_CanExecute(obj As Object) As Boolean
    125. Return Not String.IsNullOrEmpty(FilterText) OrElse FilterStartdate IsNot Nothing OrElse FilterEndDate IsNot Nothing
    126. End Function
    127. Private Sub ResetFilterCommand_Execute(obj As Object)
    128. FilterText = Nothing : FilterStartdate = Nothing : FilterEndDate = Nothing
    129. End Sub
    130. Private _openwebsitecommand As ICommand
    131. Public Property OpenWebsiteCommand() As ICommand
    132. Get
    133. If _openwebsitecommand Is Nothing Then
    134. _openwebsitecommand = New Helper.RelayCommand(AddressOf OpenWebsiteCommand_Execute, AddressOf OpenWebsiteCommand_CanExecute)
    135. End If
    136. Return _openwebsitecommand
    137. End Get
    138. Set(ByVal value As ICommand)
    139. _openwebsitecommand = value
    140. End Set
    141. End Property
    142. Private Function OpenWebsiteCommand_CanExecute(obj As Object) As Boolean
    143. Return True
    144. End Function
    145. Private Sub OpenWebsiteCommand_Execute(obj As Object)
    146. Dim p As New Process
    147. p.StartInfo.FileName = "http://www.happyfeets.de"
    148. p.Start()
    149. End Sub
    150. Private _deleteauftragcommand As ICommand
    151. Public Property DeleteAuftragCommand() As ICommand
    152. Get
    153. If _deleteauftragcommand Is Nothing Then
    154. _deleteauftragcommand = New Helper.RelayCommand(AddressOf DeleteAuftragCommand_Execute, AddressOf DeleteAuftragCommand_CanExecute)
    155. End If
    156. Return _deleteauftragcommand
    157. End Get
    158. Set(ByVal value As ICommand)
    159. _deleteauftragcommand = value
    160. End Set
    161. End Property
    162. Private Function DeleteAuftragCommand_CanExecute(obj As Object) As Boolean
    163. Return Auftraege.Count > 0 AndAlso ListBoxSelectedItem IsNot Nothing
    164. End Function
    165. Private Sub DeleteAuftragCommand_Execute(obj As Object)
    166. Auftraege.Remove(ListBoxSelectedItem)
    167. End Sub
    168. Private _editauftragcommand As ICommand
    169. Public Property EditAuftragCommand() As ICommand
    170. Get
    171. If _editauftragcommand Is Nothing Then
    172. _editauftragcommand = New Helper.RelayCommand(AddressOf EditAuftragCommand_Execute, AddressOf EditAuftragCommand_CanExecute)
    173. End If
    174. Return _editauftragcommand
    175. End Get
    176. Set(ByVal value As ICommand)
    177. _editauftragcommand = value
    178. End Set
    179. End Property
    180. Private Function EditAuftragCommand_CanExecute(obj As Object) As Boolean
    181. Return Auftraege.Count > 0 AndAlso ListBoxSelectedItem IsNot Nothing
    182. End Function
    183. Private Sub EditAuftragCommand_Execute(obj As Object)
    184. MessageBox.Show(ListBoxSelectedItem.ToString & "könntma editen")
    185. ListBoxSelectedItem = Nothing
    186. End Sub
    187. Private _addauftragcommand As ICommand
    188. Public Property AddAuftragCommand() As ICommand
    189. Get
    190. If _addauftragcommand Is Nothing Then
    191. _addauftragcommand = New Helper.RelayCommand(AddressOf AddAuftragCommand_Execute, AddressOf AddAuftragCommand_CanExecute)
    192. End If
    193. Return _addauftragcommand
    194. End Get
    195. Set(ByVal value As ICommand)
    196. _addauftragcommand = value
    197. End Set
    198. End Property
    199. Private Function AddAuftragCommand_CanExecute(obj As Object) As Boolean
    200. Return True
    201. End Function
    202. Private Sub AddAuftragCommand_Execute(obj As Object)
    203. MessageBox.Show("könntma anlegen")
    204. End Sub
    205. #End Region
    206. #Region "Funktionen"
    207. Sub CreateSampleAuftraege()
    208. For i As Integer = 0 To 90
    209. Auftraege.Add(New AuftragModel(i + 1, DateTime.Now.AddDays(i), $"Mahadma {(i + 1).ToString}", 20 + i))
    210. Next
    211. End Sub
    212. #End Region
    213. #Region "INotifyPropertyChanged"
    214. 'Imports System.ComponentModel
    215. 'Imports System.Runtime.CompilerServices
    216. 'Implements INotifyPropertyChanged
    217. Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
    218. Protected Overridable Sub RaisePropertyChanged(<CallerMemberName> Optional ByVal prop As String = "")
    219. RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(prop))
    220. End Sub
    221. #End Region
    222. End Class




    Bin mir leider nicht sicher, wie genau du das bei Brutto/Netto mit den ReadOnly Propertys meinst, habe dir die Aktuelle AuftragsModelKlasse mal eingefügt.
    AuftragsModel:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.ComponentModel
    2. Imports System.Runtime.CompilerServices
    3. Public Class AuftragModel
    4. Implements INotifyPropertyChanged
    5. Public Sub New()
    6. End Sub
    7. Public Sub New(ByVal nIndx As Integer, ByVal nDate As DateTime?, ByVal nKundeName As String, ByVal nBruttoPreis As Decimal)
    8. AuftragsNummer = nIndx
    9. AuftragsDatum = nDate
    10. KundenName = nKundeName
    11. BruttoPreis = nBruttoPreis
    12. End Sub
    13. #Region "Propertys"
    14. Private _auftragsnummer As Integer = 0
    15. Public Property AuftragsNummer() As Integer
    16. Get
    17. Return _auftragsnummer
    18. End Get
    19. Set(ByVal value As Integer)
    20. _auftragsnummer = value
    21. RaisePropertyChanged()
    22. End Set
    23. End Property
    24. Private _auftragsdatum As DateTime?
    25. Public Property AuftragsDatum() As DateTime?
    26. Get
    27. Return _auftragsdatum
    28. End Get
    29. Set(ByVal value As DateTime?)
    30. _auftragsdatum = value
    31. RaisePropertyChanged()
    32. End Set
    33. End Property
    34. Private _kundenname As String = "unbenannt"
    35. Public Property KundenName() As String
    36. Get
    37. Return _kundenname
    38. End Get
    39. Set(ByVal value As String)
    40. _kundenname = value
    41. RaisePropertyChanged()
    42. End Set
    43. End Property
    44. Private _bruttopreis As Decimal = 0
    45. Public Property BruttoPreis() As Decimal
    46. Get
    47. Return _bruttopreis
    48. End Get
    49. Set(ByVal value As Decimal)
    50. _bruttopreis = value
    51. RaisePropertyChanged()
    52. Mehrwertsteuer = getMwSt(value)
    53. NettoPreis = getNetto(value, Mehrwertsteuer)
    54. End Set
    55. End Property
    56. Private _mehrwertsteuer As Decimal = 0
    57. Public Property Mehrwertsteuer() As Decimal
    58. Get
    59. Return _mehrwertsteuer
    60. End Get
    61. Set(ByVal value As Decimal)
    62. _mehrwertsteuer = value
    63. RaisePropertyChanged()
    64. End Set
    65. End Property
    66. Private _nettopreis As Decimal = 0
    67. Public Property NettoPreis() As Decimal
    68. Get
    69. Return _nettopreis
    70. End Get
    71. Set(ByVal value As Decimal)
    72. _nettopreis = value
    73. RaisePropertyChanged()
    74. End Set
    75. End Property
    76. #End Region
    77. #Region "Funktionen"
    78. Private Function getMwSt(value As Decimal) As Decimal
    79. Return (value / 100) * 19
    80. End Function
    81. Private Function getNetto(value As Decimal, MwSt As Decimal) As Decimal
    82. Return value - MwSt
    83. End Function
    84. Public Overrides Function ToString() As String
    85. Dim tmpDate As DateTime
    86. If DateTime.TryParse(AuftragsDatum.ToString, tmpDate) Then
    87. Return $"{AuftragsNummer} / {tmpDate.ToShortDateString} / {KundenName}"
    88. Else
    89. Return $"{AuftragsNummer} / {AuftragsDatum} / {KundenName}"
    90. End If
    91. End Function
    92. #End Region
    93. #Region "INotifyPropertyChanged"
    94. 'Imports System.ComponentModel
    95. 'Imports System.Runtime.CompilerServices
    96. 'Implements INotifyPropertyChanged
    97. Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
    98. Protected Overridable Sub RaisePropertyChanged(<CallerMemberName> Optional ByVal prop As String = "")
    99. RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(prop))
    100. End Sub
    101. #End Region
    102. End Class
    If Energy = Low Then
    Drink(aHugeCoffee)
    Else
    Drink(aHugeCoffeeToo)
    End If

    asusdk schrieb:

    10 Items zu je 20 € Brutto in der Listbox <-> Ein Label mit 200 € Brutto in dem Usercontrol.

    OK, also wie ich dachte. Die Summe.

    asusdk schrieb:

    Denke ich hier evtl. in die verkehrte Richtung ?

    Nene, passt schon, du denkst nur immer zu stark an Controls. Beim Binding musst du immer an Daten denken. Und du BINDEST dann an die Daten.

    asusdk schrieb:

    eine ViewModelKlasse gibt es nicht im direkten Sinne, mein "ViewModel" ist der Codebehind des Window

    Das passt schon. Dann ist die CodeBehind ja quasi dein ViewModel.

    asusdk schrieb:

    Bin mir leider nicht sicher, wie genau du das bei Brutto/Netto mit den ReadOnly Propertys meinst

    Naja, im Model ist es nicht so prikelnd wenn man sowohl Brutto als auch Netto Preis speichert. Wozu auch? Habe ich einen der beiden Werte und den MwSt Satz benötige ich den anderen Wert nicht. Nettowert + MwSt-Betrag = Bruttowet ODER Bruttowert - MwSt-Betrag = Nettowert
    Warum also beide Werte speichern? Ist imho unnötig oder? Aber gut.

    Ich werde dir mal ein kleines Beispiel zusammenschustern welches dein Problem so verständlich wie möglich klarlegt.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##


    Ich werde dir mal ein kleines Beispiel zusammenschustern welches dein Problem so verständlich wie möglich klarlegt.

    Cool, danke dir vielmals !


    Naja, im Model ist es nicht so prikelnd wenn man sowohl Brutto als auch Netto Preis speichert. Wozu auch? Habe ich einen der beiden Werte und den MwSt Satz benötige ich den anderen Wert nicht. Nettowert + MwSt-Betrag = Bruttowet ODER Bruttowert - MwSt-Betrag = Nettowert
    Warum also beide Werte speichern? Ist imho unnötig oder? Aber gut.

    Nene, da bin ich ganz und gar bei dir, aber ich brauch die Propertys ja, damit ich an diese binden kann oder nicht ? und da nur der Bruttowert gesetzt wird muss ich doch wenn dieser gesetzt wird auch Netto/MwSt setzen ?


    LG und Danke dir wirklich sehr =)
    If Energy = Low Then
    Drink(aHugeCoffee)
    Else
    Drink(aHugeCoffeeToo)
    End If

    asusdk schrieb:

    aber ich brauch die Propertys ja, damit ich an diese binden kann oder nicht ?


    Und genau da sind wir wieder bei dem Punkt wo so manche meinen das es schon klar geht in die Model Klasse INotifyPropertyChanged zu implementieren und diese Klasse dann gleich als ViewModel KLasse direkt zum Binden zu verwenden. Wo ich immer sage das dies nicht so dolle ist. Genau wegen sowas. Die Modelklasse will ich ja meisst Persistieren. Also zum speichern verwenden. Egal ob nun als XML, in ne Datenbank oder weis der Teufel wohin. Aber das Modelklasse ist so gut wie immer zum persistieren da. Und da kommt man früher oder später an einen Punkt wo genau dies eher doof ist. So wie hier.
    Klar, man kann meinen das es mehr arbeit ist einen "Wrapper" zu erstellen und somit noch eine Klasse mehr reinkloppt aber felxibler ist es allemal.

    In diesem Fall hätte ich eben eine Auftrag klasse. Das ist die Model Klasse. Und eine AuftragViewModel Klasse. Das ist die Klasse welche verwendet wird um die "Sicht" zu bedienen. Also rein die KLasse auf die gebunden wird. Die Properties in dieser Klasse "Returnen" nur die Properties aus der Modelinstanz und setzen diese auch wieder.

    Das klingt nun etwas komisch aber so isrt das eben viel flexibler. Schau dir einfach mal die Klassen an und wenn du Fragen hast Frag einfach.

    Zur Erklärung:

    Es gibt ein Model: Auftrag
    Es gibt ein "normales" ViewModel: AuftragViewModel
    Und ein ViewModel auf welches das MainWindow gebunden ist um einfach das VieWModel übersichtlicher zu halten. Das ist das AuftragPAgeViewModel.

    Wie gesagt, frag einfach, gerne gehe ich es mit dir durch, ich weis du magst es nicht wenn man viele Klassen verwendet, aber glaub mir, hast du es mal raus ist es tatsächlich übersichtlicher.

    Schöne Grüße
    Sascha
    Bilder
    • Anmerkung 2019-12-23 211618.jpg

      211,45 kB, 1.572×892, 156 mal angesehen
    Dateien
    • AsusSumDemo.zip

      (232,44 kB, 159 mal heruntergeladen, zuletzt: )
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Hi Sascha,

    beim überfliegen deines Projekts bin ich auf eine für mich grundlegende Frage gestoßen und ich hoffe du kannst mir diese beantworten, bislang hatte ich MVVM (Ich hoffe ich verwende den Begriff hier Richtig) folgendermaßen im Kopf/vor Auge, DatenModel > ViewModel > View = MVVM aber wenn ich mir dein Projekt ansehe, scheint mir das es eher DatenModel > Mehrere VieModels (je nach Item nenn ichs jetzt mal) > ViewModel welche die GUI wiederspiegelt, welcher man die zuvor erstellten ViewModels unterordnet, so wird denk ich langsam der sprichwörtliche Schuh draus, falls ich denn richtig liege, dann versteh ich das Prinzip schon mal im Grunde, muss noch an dem Teil mit dem Verbinden der verschiedenen ViewModels arbeiten 8|

    Werd mich mal weiter in dein Sample einarbeiten, danke schon mal

    LG
    If Energy = Low Then
    Drink(aHugeCoffee)
    Else
    Drink(aHugeCoffeeToo)
    End If
    Das hast du schon richtig verstanden.

    Wichtig hierbei ist das du dich jetzt nicht auf die Benamsung stützt bzw. den "ViewModel" Teil von MVVM nicht auf die KLassen (Dateinamen -> Klassennamen) zurückführst. Ist ist einfach nur eine Konvention das man Klassen welche die View "beschreiben" einfach mit BlaBlaViewModel benamst. Das bedeutet aber nicht das dies gleich der ViewModel-Teil von MVVM ist. M-V-VM beschreibt die "Layer". Denn normalerweise trennt man bei korrektem MVVM die Layer. MAn hat also bei M-V-VM drei Projekte in der Projektmappe (mindestens).

    Insofern ist das von mir hochgeladene Projekt auch KEIN MVVM konformes Projekt. Es folgt lediglich der "Leere" eine View-Klasse zu haben auf welche die View gebunden ist (über Binding) ohne CodeBehind. Zusätzlich führe ich eben gerne eine Zwischenklasse für Modelklassen ein wie in dem Beispiel ein AuftragViewModel für die Model-Klasse "Auftrag". Ja, diese endet mit "ViewModel" aber das muss ja nicht bedeuten das es ein MVVM Projekt ist. Das macht man einfach dafür das man eben weis: OK, das ist eine Klasse für die View welche eine Instanz eines "Auftrag-Modelobjekts" hält auf welche ich binden kann.

    Dann habe ich eben eine AuftragPageViewModel Klasse welche eine "Page" oder ein View wenn man so will representiert. Auch das weis ich anhand der Benamsung. Das "Page" sagt mir das ich damit ein Fenster (also ein ganzes View) damit verwalte und es in diesem um Aufträge geht. Eigendlich sollte diese Klasse sogar "AufträgePageViewModel" heißen, aber das ist schon mal durch das Umlaut a doof. Was auch der Grund ist warum ich immer in Englisch benenne.

    Ich habe also ein AuftragPageViewModel. Eine Klasse welche sich um die Aufträge und alles was dazu gehört kümmert. Löschen, Hinzufügen, Filtern bearbeiten usw.
    Innerhalb dieser Klasse gibt es eine Auflistung von Aufträgen. ObservableCollection(Of AuftragViewModel). Richtig. Keine Auflistung der Model Klasse "Auftrag" sondern die ViewModel-Klasse weil diese INotifyPropertyChanged implementiert. Durch den Konstruktor welchem ich ein Auftrag-Model Objekt übergeben kann ist die Collection auch einfach zu füllen. Den Rest übernimmt die Klasse selbst.

    Wenn du dir das ansiehst wirst du erkennen das es zwar im ersten Augenblick vieleicht unnötig kompliziert wirkt und dir vieleicht sogar sauer aufstoßen wird jetzt extra ne Klasse zu haben welche einfach nur die Eigenschaften den Model-Objekts weitergibt bzw. wieder darin speichert aber wie wir gesehen haben ist es in vielen Fällen durchaus sinnvoll weil vieleicht im View andere Dinge angezeigt oder bearbeitet werden sollen als am Ende vieleicht gespeichert werden sollen. Und bedenke - du hast hier noch nicht mal ein kompliziertes Model. Sobald da was mit diversen Berechnungen gemacht wird kommst du mit einem Model alleine nicht mehr weit und hast dann beim speichern enorme Probleme. So bist du selbst Herr der lage was du wie speicherst und was du wie anzeigen willst.

    Ich hoffe das war ausführlich und verständlich genug. Evtl. musst du dir den Text mehrmals durchlesen um ihn zu verstehen - aller Anfang ist schwer. Bei Fragen kannst du einfach Fragen, dafür ist das Forum ja da.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Hi Sascha, und solltest du es heute noch lesen Frohe Weihnachten andernfalls schönen Feiertag =)

    also ich bin auf jeden Fall dabei das Projekt nochmals extra mit einem ViewModel umzusetzen, da deine erklärung zwar noch kompliziert, aber einleuchtend klingt.

    Allerdings ist mir bei deiner Demo aufgefallen, das sich die "Werte" leider nur aktualisieren, wenn ein Filter angewandt wird, ändert sich ein Item, oder wird eines aus der Liste entfernt, ändert sich der Inhalt des Labels leider nicht, (ich vermute das liegt daran, das BruttoSum (auf welches ich gebunden habe) ja nur eine ReadOnly Property ist, somit kein "PropertyChanged" raised) womit ich wieder bei quasi selber funktionalität bin, wie bereits zu beginn dieses Threads.

    Evtl. hast du eine Idee wie sich das bewerkstelligen lassen könnte ?

    LG
    If Energy = Low Then
    Drink(aHugeCoffee)
    Else
    Drink(aHugeCoffeeToo)
    End If

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „asusdk“ ()

    Hallo und danke für die Glückwünsche, gebe ich zurück.

    asusdk schrieb:

    Evtl. hast du eine Idee wie sich das bewerkstelligen lassen könnte ?

    Sicher habe ich eine Idee.

    Aber damit ich es dir nicht einfach nur vormache....

    Was willst du? Du willst das du im AuftragPageViewModel über eine Änderung der Werte des Property NettoPreis oder MwStSatz des AuftragViewModel benachrichtigt wirst. OK, dann packst du einfach ein Event in die AuftragViewModel-Klasse wie z.b.:

    VB.NET-Quellcode

    1. Friend Event CalculatingChanged()


    Im Setter der beiden Properties wirfst du dieses Event:

    VB.NET-Quellcode

    1. Public Property NettoPreis As Decimal
    2. Get
    3. Return _auftragModel.NettoPreis
    4. End Get
    5. Set(value As Decimal)
    6. _auftragModel.NettoPreis = value
    7. RaisePropertyChanged()
    8. RaiseEvent CalculatingChanged()
    9. End Set
    10. End Property


    Gut, jetzt müssen wir im AuftragPageViewModel nur noch dieses Event abonnieren, damit die Methode RaiseSumPropertyChanged() welche wir ja bereits haben ausgeführt wird wenn in einem Auftrag dieses Event geworfen wird. Wir ändern also die MEthode CreateSampleAuftraege() ein wenig ab:

    VB.NET-Quellcode

    1. Sub CreateSampleAuftraege()
    2. For i As Integer = 0 To 90
    3. Dim newAuftrag = New AuftragViewModel(New Model.Auftrag(i + 1, DateTime.Now.AddDays(i), $"Mahadma {(i + 1).ToString}", 20 + i))
    4. AddHandler newAuftrag.CalculatingChanged, Sub() RaiseSumPropertyChanged()
    5. Auftraege.Add(newAuftrag)
    6. Next
    7. End Sub


    Und schon klappt alles.
    Du siehst schon, durch das einführen dieser Zwischenklasse bist du total frei und kannst eben einfach z.b. ein Event der Klasse hinzufügen ohne dich um die Persistierung der Aufträge sorgen zu machen, denn die Modelklasse bleibt ja unberührt. ;)

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##