WPF Filtern nach DateTime bzw. Timespan

  • WPF

Es gibt 25 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    WPF Filtern nach DateTime bzw. Timespan

    Hi an alle,

    zuallererst möchte ich mich entschuldigen sollte dies doch in den Support-Thread zum WPF-Tutorial gehören, da jedoch bei Punkt 2.1.4.6 - Binding an Collections mit CollectionViewSource (genauer gesagt das Filtern) nur anhand von Text/String gezeigt wurde, und ich ja eher an DateTime denke, dachte ich, das es nicht explizit in den Support Thread gehört, falls doch, dann bitte verschieben.

    Ich habe heute einige Stunden damit herumprobiert, den im Tutorial gezeigten Filter der IcollectionView anstelle von Text/String, mit einem DateTimeObject zu verwenden (rein zum testen/üben), dabei bin ich auf mehrere Hürden gestoßen.

    Ein DateTimeObjekt scheint nicht Nothing sein zu können, stattdessen wird schlicht das früheste Datum verwendet (01.01.0001) was in meinem Test zu folgendem Filter geführt hat (hoffentlich nicht ganz verhunzt):

    VB.NET-Quellcode

    1. Function AuftragsListeViewFilter(obj As Object) As Boolean
    2. If AuftragsListeFilterDate = DateTime.MinValue Then Return True
    3. If obj IsNot Nothing Then
    4. Dim CurrentAuftrag As Auftrag = CType(obj, Auftrag)
    5. If Not CurrentAuftrag.Auftragsdatum = DateTime.MinValue Then
    6. Return CurrentAuftrag.Auftragsdatum.Date = AuftragsListeFilterDate.Date
    7. Else
    8. Return True
    9. End If
    10. Else
    11. Return True
    12. End If
    13. End Function


    Soweit so gut, das Filtern funktioniert, aber ich vermute das es hier doch sicher einen besseren Weg gibt ? Denn verwende ich hier z.B. TwoWayBinding, zeigt mein DatePicker natürlich auch das "unangenehme" Datum an. (habe mir hier mit OneWayToSourceBinding einen nicht sehr schönen Workaround geschaffen)



    Allerdings, würde ich idealerweise, eigentlich 2 DatePicker verwenden, einmal "Von" und einmal "Bis" aber, das wiederrum führt ja dazu (wenn ich richtig liege) das ich dann anhand einer TimeSpan arbeiten müsste.


    Als ich noch versucht habe ohne Binding zu erbeiten, konnte ich "leichter" bestimmen was nun angezeigt werden soll und was nicht, aber da ich es nun über binding versuchen möchte, würde ich sehr gerne Fragen, wie ich das am besten lösen kann ?

    Denn rein theoretisch (zumindest stelle ich es mir aktuell so vor) bräuchte ich dann ja 2 Propertys einmal für das startdatum, einmal für das Enddatum, ein weiteres für die daraus zu errechnende TimeSpan, und dann einen Filter der Feststellen kann ob das jeweilige Item unter dem Property Auftragsdatum irgendwo in diesem TimeSpan liegt.

    Aber hier kommt vermutlich die Crux am ganzen, was ist denn nun, wenn ich möchte, das wenn z.B. nur ein Von-Datum eingegeben wird , alle aufträge die Ab diesem Datum dabei sind, bis hin zu einem unbestimmten Datum angezeigt werden, und dasselbe auch umgekehrt, wird also nur ein Bis-Datum angegeben, das dann nur angezeigt wird was vor diesem Datum passierte.

    Ich möchte im prinzip einfach mal fragen ob ich zumindest theoretsich den richtigen Gedankenweg habe, und ich würde gerne wissen, wie ich so etwas evtl. in elegant lösen könnte, besonders bezogen auf Von-Bis.


    Ich hoffe ich habe mich einigermaßen verständlich ausgedrückt.


    LG


    p.S. sollte die Antwort darauf irgendwo im WPF-Tutorial bereits erwähnt sein, so bitte ich tausendfach um Entschuldigung, ich versuche mich gerade ein wenig in die WPF einzuarbeiten, vor allem auf Basis des Tutorials, aber ich hatte bislang noch nicht die Zeit jedes Kapitel durchzuarbeiten.
    If Energy = Low Then
    Drink(aHugeCoffee)
    Else
    Drink(aHugeCoffeeToo)
    End If

    asusdk schrieb:

    Als ich noch versucht habe ohne Binding zu erbeiten, konnte ich "leichter" bestimmen was nun angezeigt werden soll und was nicht

    Aber nur wenn du nicht mit den richtigen Datentypen und/oder Option Strict Off programmiert hast. Denn sonst hättest du ja genauso die Datentypen wie hier jetzt. Also kommt es aufs selbe raus.

    asusdk schrieb:

    Ein DateTimeObjekt scheint nicht Nothing sein zu können

    Warum nicht? Mach dein Property zu einem Nullable(Of Date) oder in der Kurzform Public Property StartDate as Date?
    Das Fragezeichen markiert es als Nullable, somit kann das Datum auch Nothing sein.

    asusdk schrieb:

    ein weiteres für die daraus zu errechnende TimeSpan, und dann einen Filter der Feststellen kann ob das jeweilige Item unter dem Property Auftragsdatum irgendwo in diesem TimeSpan liegt.

    Du brauchst kein Timespan. Du musst nur im Code abfragen ob das eingegebe Datum >= Von und <= Bis ist. Mehr ist es dich nicht.

    Also If MyFilterDate >= StartDate AndAlso MyFilterDate <= EndDate. Zumindest wenn ich dich richtig verstanden haben sollte.

    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. ##

    Aber nur wenn du nicht mit den richtigen Datentypen und/oder Option Strict Off programmiert hast. Denn sonst hättest du ja genauso die Datentypen wie hier jetzt. Also kommt es aufs selbe raus.


    nein, ich programmiere seit 2 Jahren mit Option Strict on, und datentyp war auch korrekt ich meinte das im Sinne von (BeispielCode):

    Filter:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Sub ExecuteFilter()
    2. Dim selectedKunde As Kunde = Nothing
    3. Dim DateStart As DateTime = Nothing
    4. Dim DateEnd As DateTime = Nothing
    5. If cb_Kunde.SelectedItem IsNot Nothing Then
    6. selectedKunde = DirectCast(cb_Kunde.SelectedItem, Kunde)
    7. End If
    8. If dp_Von.SelectedDate IsNot Nothing Then
    9. DateStart = dp_Von.SelectedDate
    10. End If
    11. If dp_Bis.SelectedDate IsNot Nothing Then
    12. DateEnd = dp_Bis.SelectedDate
    13. End If
    14. loadAFwithFilter(selectedKunde, DateStart, DateEnd)
    15. End Sub

    LadeListemitFilter

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Sub loadAFwithFilter(ByVal selectedKunde As Kunde, ByVal DateStart As DateTime, ByVal DateEnd As DateTime)
    2. Dim tmp_mainlist As New List(Of Auftrag)
    3. tmp_mainlist = Back.AuftragsListe
    4. Dim tmp_ListOfAuftraege As New List(Of Auftrag)
    5. If selectedKunde IsNot Nothing Then
    6. For Each aft As Auftrag In tmp_mainlist
    7. If aft.Kunde.getKundeFullName = selectedKunde.getKundeFullName Then
    8. tmp_ListOfAuftraege.Add(aft)
    9. End If
    10. Next
    11. Else
    12. tmp_ListOfAuftraege = tmp_mainlist
    13. End If
    14. If DateStart <> Nothing Then
    15. Dim tmp_ListOfAuftraege2 As New List(Of Auftrag)
    16. For Each aft As Auftrag In tmp_ListOfAuftraege
    17. If DateStart <= aft.Auftragsdatum Then
    18. tmp_ListOfAuftraege2.Add(aft)
    19. End If
    20. Next
    21. tmp_ListOfAuftraege = tmp_ListOfAuftraege2
    22. End If
    23. If DateEnd <> Nothing Then
    24. Dim tmp_ListOfAuftraege3 As New List(Of Auftrag)
    25. For Each aft As Auftrag In tmp_ListOfAuftraege
    26. If DateEnd >= aft.Auftragsdatum Then
    27. tmp_ListOfAuftraege3.Add(aft)
    28. End If
    29. Next
    30. tmp_ListOfAuftraege = tmp_ListOfAuftraege3
    31. End If
    32. lb_Auftraege.Items.Clear()
    33. For Each aft As Auftrag In tmp_ListOfAuftraege
    34. lb_Auftraege.Items.Add(aft)
    35. Next
    36. calculateValuesOfListbox()
    37. End Sub


    also schlicht und ergreifend gänzlich manuell ^^


    Du brauchst kein Timespan. Du musst nur im Code abfragen ob das eingegebe Datum >= Von und <= Bis ist. Mehr ist es dich nicht.

    Also If MyFilterDate >= StartDate AndAlso MyFilterDate <= EndDate. Zumindest wenn ich dich richtig verstanden haben sollte.



    Ich hatte schon befürchtet das ich mich falsch ausgedrückt habe.

    Im Prinzip:
    Wpf-Window mit einem DataGrid und 2 x DatePicker

    in einem DatePicker möchte ich das Startdatum angeben, im zweiten dann das Enddatum. Soweit wäre deine Lösung ja ideal (danke dafür =) ) aber es soll die Möglichkeit bestehen, nur 1 der Beiden DatePicker zu verwenden.

    Also wenn ich Nur ein StartDatum eingebe, aber kein Enddatum, dann soll er alle Aufträge ab dem StartDatum anzeigen oder eben auch umgekehrt. Nach der obigen Lösung "MÜSSEN" ja 2 Datum(se) eingegeben werden



    Nachtrag: Nullable(Of Date) lässt sich durchaus machen, allerdings steht dann z.B. DateTime.Date nicht mehr zur verfügung, da es kein Richtiges Date mehr zu sein scheint.
    If Energy = Low Then
    Drink(aHugeCoffee)
    Else
    Drink(aHugeCoffeeToo)
    End If

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

    Also als erstes muss ich jetzt mal sagen das du hier Bananen und Äpfel nicht verwenchseln darfst. Die Prozedur welche du hier gepostet hast hat mal mit einem Filter nix zu tun.
    Du lädst ja nur gewisse Daten, hier in der WPF versuchst du gerade zu Filtern. Die Daten sind dennoch ALLE da. Das sind schon verschiedene Dinge.
    Deine Methode loadAFwithFilter solltest du überdenken. Ich denke mit Linq kannst du die in einen drei bis vierzeiler umschreiben. Aber egal jetzt.

    asusdk schrieb:

    aber es soll die Möglichkeit bestehen, nur 1 der Beiden DatePicker zu verwenden.

    Ja, und? Dann fügst du eben diese Bedingung auch ein und prüfst ob z.b. im "Bis" ein Datum angegeben ist und nimmst nur die Bedingung mit hinein wenn dies der Fall ist.
    Ich Poste nur absichtlich keinen Code der dir zu 100% passt weil sonst der Lerneffekt für die Fische ist.

    Von der Codelogik her ist es im Grunde ja das selbe wie in deiner Prozedur beim Laden. Diese "loadAFwithFilter". Es ist genau das selbe Prinzip. Reine logik, mit Bedingungen wo am Ende True oder False rauskommt.
    Setze in der Zeile mit den Bedingungen einen Haltepunkt. Wenn dieser angelaufen wird markiere die komplette Bedingung. Dann Rechtsklick auf die Bedingung und "Überwachung hinzufügen".
    Und schon siehst du das Ergebnis. Das machst du so lange bis du dir sicher bist das dein Code stimmt und die Bedingung korrekt ist.

    Hat im Grunde nicht mal was mit der WPF zu tun. Es ist ein simples "Am ende soll ein Item gefiltert werden oder nicht" - also True oder False.
    Ich hoffejetzt wird es klarer.

    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. ##

    Ja, klarer auf jeden fall, nur stolpere ich nachwievor darüber, das Datetime nicht nichts sein kann, (jedenfalls nicht wenn es auch als Datum verwendung finden soll) Also muss ich wohl bei OneWayBinding bleiben (wodurch er mir den DatePicker leider auch rot umrahmt).
    Auch auf die Gefahr hin das wir wieder aneinander vorbeireden, aber es ist in gewissen Punkten nun mal schwieriger mit Binding zu arbeiten, weil daran immer irgendwelche bedingungen geknüpft sind. Es mag in gewisse Richtungen flexibler sein, allerdings in viele andere auch eingeschränkter.

    Das muss ich erst lernen, dazu muss ich üben und Progrämmchen schreiben. Aber leider kommen so immer wieder Probleme auf, welche ich sonst nicht hatte. Ich frag ja nicht aus Jux und tollerei, sondern weil ich hier einfach nicht weiterkomme, und du sagtest ja ich soll fragen wenn mir was nicht klar ist, das habe ich getan, aber bis auf ein paar Prozent weniger trüb, ist mir leider auch durch fragen nichts klar geworden....

    Ich erwarte und will keinen fertigen Code, nur um das klarzustellen. Aber irgendwelche Stichpunkte die auf die erwähnte Problematik eingehen, so dass binding für mich auch nutzbar wird, wären schön....
    If Energy = Low Then
    Drink(aHugeCoffee)
    Else
    Drink(aHugeCoffeeToo)
    End If
    Na dann Poste nun mal deine Klasse und dann schaun wir mal was du Momentan so hast.

    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. ##

    Mache ich gerne, ich muss aber von vornherein zugeben, das ich MVVM noch nicht drauf habe, ich arbeite aktuell im CodeBehind.

    MainWindow-Xaml:
    Spoiler anzeigen

    XML-Quellcode

    1. <Window x:Class="MainWindow"
    2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    4. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    5. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    6. xmlns:local="clr-namespace:WpfApp1"
    7. mc:Ignorable="d"
    8. Title="MainWindow" Height="450" Width="800" SizeToContent="Width">
    9. <Grid>
    10. <Grid.ColumnDefinitions>
    11. <ColumnDefinition Width="67*"/>
    12. <ColumnDefinition Width="175"/>
    13. </Grid.ColumnDefinitions>
    14. <Grid Grid.Column="0">
    15. <Grid.RowDefinitions>
    16. <RowDefinition Height="50*"/>
    17. <RowDefinition Height="50*"/>
    18. </Grid.RowDefinitions>
    19. <DataGrid Grid.Row="0" AutoGenerateColumns="True" ItemsSource="{Binding KundenListeView}"/>
    20. <DataGrid Grid.Row="1" AutoGenerateColumns="True" ItemsSource="{Binding AuftragsListeView}"/>
    21. </Grid>
    22. <Grid Background="DimGray" Grid.Column="1">
    23. <Image Source="http://happyfeets.de/wp-content/uploads/2019/06/HappyFeetsLogoNeu.jpg" VerticalAlignment="Top" Stretch="Uniform"/>
    24. <StackPanel VerticalAlignment="Bottom">
    25. <DockPanel VerticalAlignment="Bottom">
    26. <TextBlock Text="KndF: " Foreground="White" Width="35" />
    27. <TextBox BorderThickness="0" Text="{Binding KundenListeFilterText,UpdateSourceTrigger=PropertyChanged}" Background="#FF8F8F8F"/>
    28. </DockPanel>
    29. <Canvas Background="White" Height="2"/>
    30. <DockPanel VerticalAlignment="Bottom">
    31. <TextBlock Text="VonF: " Foreground="White" Width="35" VerticalAlignment="Center"/>
    32. <DatePicker SelectedDate="{Binding AuftragsListeFilterDateStart, UpdateSourceTrigger=PropertyChanged, Mode=OneWayToSource}"/>
    33. </DockPanel>
    34. <DockPanel VerticalAlignment="Bottom">
    35. <TextBlock Text="BisF: " Foreground="White" Width="35" VerticalAlignment="Center"/>
    36. <DatePicker SelectedDate="{Binding AuftragsListeFilterDateEnde, UpdateSourceTrigger=PropertyChanged, Mode=OneWayToSource}"/>
    37. </DockPanel>
    38. </StackPanel>
    39. </Grid>
    40. </Grid>
    41. </Window>

    sieht nicht schön aus, ich weiss, bild war nur zum testen drinn, muss wohl auch das Designen noch lernen =)





    MainWindow-VB
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.Collections.ObjectModel
    2. Imports System.ComponentModel
    3. Imports System.Runtime.CompilerServices
    4. Class MainWindow
    5. Implements INotifyPropertyChanged
    6. Private Sub MainWindow_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
    7. KundenListeView = CollectionViewSource.GetDefaultView(KundenListe)
    8. KundenListeView.Filter = AddressOf KundenListeViewFilter
    9. For i As Integer = 0 To 9
    10. KundenListe.Add(New Kunde With {.KundeName = "Michael" & i.ToString})
    11. Next
    12. AuftragsListeView = CollectionViewSource.GetDefaultView(AuftragsListe)
    13. AuftragsListeView.Filter = AddressOf AuftragsListeViewFilter
    14. For i As Integer = 0 To 9
    15. AuftragsListe.Add(New Auftrag With {.Auftragsdatum = DateTime.Now, .AuftragsKunde = New Kunde With {.KundeName = "Michael" & i.ToString}.KundeName, .BruttoPreis = 20 + i})
    16. Next
    17. Me.DataContext = Me
    18. End Sub
    19. Private _kundenliste As New ObservableCollection(Of Kunde)
    20. Public Property KundenListe() As ObservableCollection(Of Kunde)
    21. Get
    22. Return _kundenliste
    23. End Get
    24. Set(ByVal value As ObservableCollection(Of Kunde))
    25. _kundenliste = value
    26. RaisePropertyChanged()
    27. End Set
    28. End Property
    29. Private _kundenlisteview As ICollectionView
    30. Public Property KundenListeView() As ICollectionView
    31. Get
    32. Return _kundenlisteview
    33. End Get
    34. Set(ByVal value As ICollectionView)
    35. _kundenlisteview = value
    36. RaisePropertyChanged()
    37. End Set
    38. End Property
    39. Private _kundenlistefiltertext As String
    40. Public Property KundenListeFilterText() As String
    41. Get
    42. Return _kundenlistefiltertext
    43. End Get
    44. Set(ByVal value As String)
    45. _kundenlistefiltertext = value
    46. KundenListeView.Refresh()
    47. RaisePropertyChanged()
    48. End Set
    49. End Property
    50. Function KundenListeViewFilter(obj As Object) As Boolean
    51. If String.IsNullOrEmpty(KundenListeFilterText) Then Return True
    52. If obj IsNot Nothing Then
    53. Dim CurrentKunde As Kunde = CType(obj, Kunde)
    54. If Not String.IsNullOrEmpty(CurrentKunde.KundeName) Then
    55. Return CurrentKunde.KundeName.ToLower.Contains(KundenListeFilterText.ToLower)
    56. Else
    57. Return True
    58. End If
    59. Else
    60. Return True
    61. End If
    62. End Function
    63. Private _auftragsliste As New ObservableCollection(Of Auftrag)
    64. Public Property AuftragsListe() As ObservableCollection(Of Auftrag)
    65. Get
    66. Return _auftragsliste
    67. End Get
    68. Set(ByVal value As ObservableCollection(Of Auftrag))
    69. _auftragsliste = value
    70. RaisePropertyChanged()
    71. End Set
    72. End Property
    73. Private _auftragslisteview As ICollectionView
    74. Public Property AuftragsListeView() As ICollectionView
    75. Get
    76. Return _auftragslisteview
    77. End Get
    78. Set(ByVal value As ICollectionView)
    79. _auftragslisteview = value
    80. RaisePropertyChanged()
    81. End Set
    82. End Property
    83. Private _auftragslistefilterdatestart As DateTime
    84. Public Property AuftragsListeFilterDateStart() As DateTime
    85. Get
    86. Return _auftragslistefilterdatestart
    87. End Get
    88. Set(ByVal value As DateTime)
    89. _auftragslistefilterdatestart = value
    90. RaisePropertyChanged()
    91. AuftragsListeView.Refresh()
    92. End Set
    93. End Property
    94. Private _auftragslistefilterdateende As DateTime
    95. Public Property AuftragsListeFilterDateEnde() As DateTime
    96. Get
    97. Return _auftragslistefilterdateende
    98. End Get
    99. Set(ByVal value As DateTime)
    100. _auftragslistefilterdateende = value
    101. RaisePropertyChanged()
    102. AuftragsListeView.Refresh()
    103. End Set
    104. End Property
    105. Function AuftragsListeViewFilter(obj As Object) As Boolean
    106. If AuftragsListeFilterDateStart = DateTime.MinValue Then Return True
    107. If obj IsNot Nothing Then
    108. Dim CurrentAuftrag As Auftrag = CType(obj, Auftrag)
    109. If Not CurrentAuftrag.Auftragsdatum = DateTime.MinValue Then
    110. Return CurrentAuftrag.Auftragsdatum.Date = AuftragsListeFilterDate.Date ' schmeisst aktuell fehler weil ich gerade am experimentieren bin und die Klasse zwischendrinn kopiert habe
    111. Else
    112. Return True
    113. End If
    114. Else
    115. Return True
    116. End If
    117. End Function
    118. Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
    119. Protected Overridable Sub RaisePropertyChanged(<CallerMemberName> Optional ByVal prop As String = "")
    120. RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(prop))
    121. End Sub
    122. End Class


    Klasse-Kunde
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.ComponentModel
    2. Imports System.Runtime.CompilerServices
    3. Public Class Kunde
    4. Implements INotifyPropertyChanged
    5. Private _kundename As String = "unbenannt"
    6. Public Property KundeName() As String
    7. Get
    8. Return _kundename
    9. End Get
    10. Set(ByVal value As String)
    11. _kundename = value
    12. RaisePropertyChanged()
    13. End Set
    14. End Property
    15. Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
    16. Protected Overridable Sub RaisePropertyChanged(<CallerMemberName> Optional ByVal prop As String = "")
    17. RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(prop))
    18. End Sub
    19. End Class


    Klasse-Auftrag
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.ComponentModel
    2. Imports System.Runtime.CompilerServices
    3. Public Class Auftrag
    4. Implements INotifyPropertyChanged
    5. Private _auftragsdatum As DateTime = DateTime.Now
    6. Public Property Auftragsdatum() As DateTime
    7. Get
    8. Return _auftragsdatum
    9. End Get
    10. Set(ByVal value As DateTime)
    11. _auftragsdatum = value
    12. RaisePropertyChanged()
    13. End Set
    14. End Property
    15. Private _auftragskunde As String
    16. Public Property AuftragsKunde() As String
    17. Get
    18. Return _auftragskunde
    19. End Get
    20. Set(ByVal value As String)
    21. _auftragskunde = value
    22. RaisePropertyChanged()
    23. End Set
    24. End Property
    25. Private _bruttopreis As Decimal = 0
    26. Public Property BruttoPreis() As Decimal
    27. Get
    28. Return _bruttopreis
    29. End Get
    30. Set(ByVal value As Decimal)
    31. _bruttopreis = value
    32. RaisePropertyChanged()
    33. End Set
    34. End Property
    35. Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
    36. Protected Overridable Sub RaisePropertyChanged(<CallerMemberName> Optional ByVal prop As String = "")
    37. RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(prop))
    38. End Sub
    39. End Class



    Damit versuche ich gerade zum üben eine Simple AuftragsListe im DataGrid zu erstellen. aktuell erstmal um das filtern zu üben. Ich weiss vieles passt noch nicht, aber zumindest sollten die Benamsungen schon mal einndeutig sein (hoffe ich zumindest)
    If Energy = Low Then
    Drink(aHugeCoffee)
    Else
    Drink(aHugeCoffeeToo)
    End If

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

    asusdk schrieb:

    nur stolpere ich nachwievor darüber, das Datetime nicht nichts sein kann
    Wie NoFear schon sagt - dafür gibts die Nullable(Of Date)-Struktur - und DatePicker.SelectedDate hat auch diesen Datentyp (deine AuftragsListeFilterDateEnde-(was für ein umständlicher Name!!)-Property aber nicht).
    Mir scheint das Problem aber auch, dass man mit einem DatePicker nicht "kein Datum" auswählen kann (hab bisher jdfs. nix gefunden).
    Da muss man dann noch einen Extra-Button anbringen, der den Wert auf Nothing setzt.



    edit: Ok, habichmich mal dran verkünstelt
    habe den DTPs checkboxen zugeordnet, mit denen man das gewählte Datum auf Nothing setzen kann.
    (Ich hoffe nur, dasses das nicht so ähnlich schon gibt, und ich das Rad nur malwieder neu erfunden hab.)

    Ausserdem habich dem Window einen DataContext im Xaml verpasst - das ist ja eine Quälerei, händisch Bindings formulieren zu müssen.
    Siehe unbedingt Grundlagen - MVVM: "Binding-Picking" im Xaml-Editor - wie angenehm Wpf programmieren eiglich sein kann.

    Allerdings habich das Gefühl, dass du dir (mal wieder?) einen höchst umständlichen Lernweg wählst.
    Imo ist das keine gute Idee, sich mit Unzulänglichkeiten von DatePickern rumzuärgern, und mit CollectionView-Filtern rumzumurksen, wenn man das mit dem Databinding noch nicht wirklich geschnackelt hat (MVVM).
    Ich hab wie gesagt, deim Window einen Xaml-Datacontext angedeihen lassen, um BindingPicking verfügbar zu haben, aber weil du statt MVVM umzusetzen "einfach" das Window selbst als sein eigenen DataContext zuweist, bietet der BindingPicking-Editor halt alle Properties der Window-Klasse an (hunderte!) statt nur die wesentlichen Properties (wie AuftragsListeFilterDateStart, AuftragsListeFilterDateEnde)
    Dateien

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „ErfinderDesRades“ ()

    (deine AuftragsListeFilterDateEnde-(was für ein umständlicher Name!!)

    Ja er ist lang, aber Benamungen sollen ja Eindeutig sein, nicht zu verwechseln eben, und Sie sollen ersichtlich machen wofür diese da sind, meistens kommen dan eben solche klopper raus ^^

    Siehe unbedingt Grundlagen - MVVM: "Binding-Picking" im Xaml-Editor - wie angenehm Wpf programmieren eiglich sein kann.

    jetzt nur kurz überflogen (bin auf dem Sprung zur arbeit) aber ich ahbe da nichts gefunden was einen DataContext setzt? Naja vermutlich im Video, werd mir das heut Abend mal angucken (in deinem angehängten Project ist es wohl das hier ? : d:DataContext="{x:Type local:MainWindow}")

    Imo ist das keine gute Idee, sich mit Unzulänglichkeiten von DatePickern rumzuärgern, und mit CollectionView-Filtern rumzumurksen, wenn man das mit dem Databinding noch nicht wirklich geschnackelt hat (MVVM).

    Die beste Idee ist es sicherlich nicht, aber MVVM ist irgendwann mal das Ziel, wenn alles andere sitzt, kann man sich um den EndGegner kümmern.


    Mir scheint das Problem aber auch, dass man mit einem DatePicker nicht "kein Datum" auswählen kann (hab bisher jdfs. nix gefunden).

    war im manuellen ganz simpel einfach: dp_Bis.SelectedDate = Nothing und schwups hats gepasst - beim Binding mus man halt einen kleinen Umweg in kauf nehmen, denk ich mal

    Genauer guck ich mir dein angehangenes Projekt dann gleich in der Arbeit an, konnte es gerade nur überfliegen.

    Danke dir für die Hilfe =)
    If Energy = Low Then
    Drink(aHugeCoffee)
    Else
    Drink(aHugeCoffeeToo)
    End If

    asusdk schrieb:

    war im manuellen ganz simpel einfach: dp_Bis.SelectedDate = Nothing und schwups hats gepasst - beim Binding mus man halt einen kleinen Umweg in kauf nehmen, denk ich mal

    Geht auch über Binding. Wenn ich hier das Property auf Nothing setze (Wenn dies ein Nullable(Of Date) - was es bei dir im Moment noch nicht ist obwohl ich das vorgeschlagen hatte) dann ist das kein Problem und wird auch vom DataPicker so übernommen das dort dann wieder "Datum wähen" drinnen steht. Ich sags jetzt glaube ich zum zehnten mal. Was "manuell" machbar ist geht auch mdit Binding. Wenn auch oft anders.

    So,@ErfinderDesRades hat recht, das DatePicker hat vom View aus gesehen keine möglichkeit Nothing zu setzen, das ist der Knackpunkt.
    Solange du aber den BindingMode OneWayToSource drinnen hast hast du auch nicht die Möglichkeit vom Code aus das zu setzen. Wie auch, es wird ja im View nicht nachgeführt. Also mal raus damit.

    Ich habe das nun so gelöst das ich für das DatePicker ein Contextmenu erstellt habe wo der Wert zurückgesetzt wird. Simpel und einfach. z.b. das Property AuftragsListeFilterDateEnde auf Nothing setzen und gut ists.
    AuftragsListeFilterDateEnde = Nothing

    Deine FilterMethode kann dann auswerten ob ein Datum ausgewählt ist und wenn ja ob der Auftrag in diese "Range" fällt. Simpel.

    VB.NET-Quellcode

    1. Function AuftragsListeViewFilter(obj As Object) As Boolean
    2. If AuftragsListeFilterDateStart Is Nothing Then Return True
    3. Dim auftr As Auftrag = DirectCast(obj, Auftrag)
    4. Dim startDate As Date = If(AuftragsListeFilterDateStart.HasValue, AuftragsListeFilterDateStart.Value, Date.MinValue)
    5. Dim endDate As Date = If(AuftragsListeFilterDateEnde.HasValue, AuftragsListeFilterDateEnde.Value, Date.MaxValue)
    6. Return auftr.Auftragsdatum.Date >= startDate AndAlso auftr.Auftragsdatum.Date <= endDate
    7. End Function


    Mehr braucht es auch schon nicht mehr.

    CodeBehind

    VB.NET-Quellcode

    1. Class MainWindow
    2. Implements INotifyPropertyChanged
    3. Private Sub MainWindow_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
    4. KundenListeView = CollectionViewSource.GetDefaultView(KundenListe)
    5. KundenListeView.Filter = AddressOf KundenListeViewFilter
    6. For i As Integer = 0 To 9
    7. KundenListe.Add(New Kunde With {.KundeName = "Michael" & i.ToString})
    8. Next
    9. AuftragsListeView = CollectionViewSource.GetDefaultView(AuftragsListe)
    10. AuftragsListeView.Filter = AddressOf AuftragsListeViewFilter
    11. For i As Integer = 0 To 9
    12. AuftragsListe.Add(New Auftrag With {.Auftragsdatum = DateTime.Now, .AuftragsKunde = New Kunde With {.KundeName = "Michael" & i.ToString}.KundeName, .BruttoPreis = 20 + i})
    13. Next
    14. Me.DataContext = Me
    15. End Sub
    16. Private _kundenliste As New ObservableCollection(Of Kunde)
    17. Public Property KundenListe() As ObservableCollection(Of Kunde)
    18. Get
    19. Return _kundenliste
    20. End Get
    21. Set(ByVal value As ObservableCollection(Of Kunde))
    22. _kundenliste = value
    23. RaisePropertyChanged()
    24. End Set
    25. End Property
    26. Private _kundenlisteview As ICollectionView
    27. Public Property KundenListeView() As ICollectionView
    28. Get
    29. Return _kundenlisteview
    30. End Get
    31. Set(ByVal value As ICollectionView)
    32. _kundenlisteview = value
    33. RaisePropertyChanged()
    34. End Set
    35. End Property
    36. Private _kundenlistefiltertext As String
    37. Public Property KundenListeFilterText() As String
    38. Get
    39. Return _kundenlistefiltertext
    40. End Get
    41. Set(ByVal value As String)
    42. _kundenlistefiltertext = value
    43. KundenListeView.Refresh()
    44. RaisePropertyChanged()
    45. End Set
    46. End Property
    47. Function KundenListeViewFilter(obj As Object) As Boolean
    48. If String.IsNullOrEmpty(KundenListeFilterText) Then Return True
    49. If obj IsNot Nothing Then
    50. Dim CurrentKunde As Kunde = CType(obj, Kunde)
    51. If Not String.IsNullOrEmpty(CurrentKunde.KundeName) Then
    52. Return CurrentKunde.KundeName.ToLower.Contains(KundenListeFilterText.ToLower)
    53. Else
    54. Return True
    55. End If
    56. Else
    57. Return True
    58. End If
    59. End Function
    60. Private _auftragsliste As New ObservableCollection(Of Auftrag)
    61. Public Property AuftragsListe() As ObservableCollection(Of Auftrag)
    62. Get
    63. Return _auftragsliste
    64. End Get
    65. Set(ByVal value As ObservableCollection(Of Auftrag))
    66. _auftragsliste = value
    67. RaisePropertyChanged()
    68. End Set
    69. End Property
    70. Private _auftragslisteview As ICollectionView
    71. Public Property AuftragsListeView() As ICollectionView
    72. Get
    73. Return _auftragslisteview
    74. End Get
    75. Set(ByVal value As ICollectionView)
    76. _auftragslisteview = value
    77. RaisePropertyChanged()
    78. End Set
    79. End Property
    80. Private _auftragslistefilterdatestart As DateTime?
    81. Public Property AuftragsListeFilterDateStart() As DateTime?
    82. Get
    83. Return _auftragslistefilterdatestart
    84. End Get
    85. Set(ByVal value As DateTime?)
    86. _auftragslistefilterdatestart = value
    87. RaisePropertyChanged()
    88. AuftragsListeView.Refresh()
    89. End Set
    90. End Property
    91. Private _auftragslistefilterdateende As DateTime?
    92. Public Property AuftragsListeFilterDateEnde() As DateTime?
    93. Get
    94. Return _auftragslistefilterdateende
    95. End Get
    96. Set(ByVal value As DateTime?)
    97. _auftragslistefilterdateende = value
    98. RaisePropertyChanged()
    99. AuftragsListeView.Refresh()
    100. End Set
    101. End Property
    102. Function AuftragsListeViewFilter(obj As Object) As Boolean
    103. If AuftragsListeFilterDateStart Is Nothing Then Return True
    104. Dim auftr As Auftrag = DirectCast(obj, Auftrag)
    105. Dim startDate As Date = If(AuftragsListeFilterDateStart.HasValue, AuftragsListeFilterDateStart.Value, Date.MinValue)
    106. Dim endDate As Date = If(AuftragsListeFilterDateEnde.HasValue, AuftragsListeFilterDateEnde.Value, Date.MaxValue)
    107. Return auftr.Auftragsdatum.Date >= startDate AndAlso auftr.Auftragsdatum.Date <= endDate
    108. End Function
    109. Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
    110. Protected Overridable Sub RaisePropertyChanged(<CallerMemberName> Optional ByVal prop As String = "")
    111. RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(prop))
    112. End Sub
    113. Private Sub ResetEndDate(sender As Object, e As RoutedEventArgs)
    114. AuftragsListeFilterDateEnde = Nothing
    115. End Sub
    116. Private Sub ResetStartDate(sender As Object, e As RoutedEventArgs)
    117. AuftragsListeFilterDateStart = Nothing
    118. End Sub
    119. End Class



    MainWindow

    XML-Quellcode

    1. <Grid>
    2. <Grid.ColumnDefinitions>
    3. <ColumnDefinition Width="67*"/>
    4. <ColumnDefinition Width="175"/>
    5. </Grid.ColumnDefinitions>
    6. <Grid Grid.Column="0">
    7. <Grid.RowDefinitions>
    8. <RowDefinition Height="50*"/>
    9. <RowDefinition Height="50*"/>
    10. </Grid.RowDefinitions>
    11. <DataGrid Grid.Row="0" AutoGenerateColumns="True" ItemsSource="{Binding KundenListeView}"/>
    12. <DataGrid Grid.Row="1" AutoGenerateColumns="True" ItemsSource="{Binding AuftragsListeView}"/>
    13. </Grid>
    14. <Grid Background="DimGray" Grid.Column="1">
    15. <Image Source="http://happyfeets.de/wp-content/uploads/2019/06/HappyFeetsLogoNeu.jpg" VerticalAlignment="Top" Stretch="Uniform"/>
    16. <StackPanel VerticalAlignment="Bottom">
    17. <DockPanel VerticalAlignment="Bottom">
    18. <TextBlock Text="KndF: " Foreground="White" Width="35" />
    19. <TextBox BorderThickness="0" Text="{Binding KundenListeFilterText,UpdateSourceTrigger=PropertyChanged}" Background="#FF8F8F8F"/>
    20. </DockPanel>
    21. <Canvas Background="White" Height="2"/>
    22. <DockPanel VerticalAlignment="Bottom">
    23. <TextBlock Text="VonF: " Foreground="White" Width="35" VerticalAlignment="Center"/>
    24. <DatePicker SelectedDate="{Binding AuftragsListeFilterDateStart, UpdateSourceTrigger=PropertyChanged}">
    25. <DatePicker.ContextMenu>
    26. <ContextMenu>
    27. <MenuItem Header="Datum zurücksetzen" Click="ResetStartDate"/>
    28. </ContextMenu>
    29. </DatePicker.ContextMenu>
    30. </DatePicker>
    31. </DockPanel>
    32. <DockPanel VerticalAlignment="Bottom">
    33. <TextBlock Text="BisF: " Foreground="White" Width="35" VerticalAlignment="Center"/>
    34. <DatePicker SelectedDate="{Binding AuftragsListeFilterDateEnde, UpdateSourceTrigger=PropertyChanged}">
    35. <DatePicker.ContextMenu>
    36. <ContextMenu>
    37. <MenuItem Header="Datum zurücksetzen" Click="ResetEndDate"/>
    38. </ContextMenu>
    39. </DatePicker.ContextMenu>
    40. </DatePicker>
    41. </DockPanel>
    42. </StackPanel>
    43. </Grid>
    44. </Grid>


    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 sags jetzt glaube ich zum zehnten mal. Was "manuell" machbar ist geht auch mdit Binding. Wenn auch oft anders.

    Ähm bitte nicht falsch verstehen, aber habe ich irgendwo in diesem Thread erwähnt das man es nicht kann ? Nein, ich sagte ja man muss einen kleinen Umweg gehen, das hast du ja mit "Wenn auch oft anders" auch gesagt.
    Du hast bereits mehrmals erwähnt (sagtest ja 10tes mal ^^) das alles in Binding möglich ist, das hab ich mir gemerkt, ich muss nur erstmal lernen soweit umzudenken, das ich die Binding-Konformen wege finde, da ich wie du es ausgedrückt hast noch extrem linear denke, daher versuche ich mich ja gerade in all den übungen, damit ich es irgendwann mal beherrsche, wie du oft genug gesagt hast, reicht tutorial lesen/video gucken nicht aus, mann muss auch damit arbeiten, was ich gerade in jeder freien Minute mache, Tutorial lesen-> video gucken-> kleines Testprojekt.

    Wenn dies ein Nullable(Of Date) - was es bei dir im Moment noch nicht ist obwohl ich das vorgeschlagen hatte

    Ja ich weiss, ich habe die Klasse, noch vor weitergehenden anpassungen gepostet, daher habe ich damit noch nicht experimentiert, nur ein schnelltest =)

    Danke euch beiden für die 2 Lösungen, dann habe ich gleich was was ich mir genauer anschauen kann =)
    If Energy = Low Then
    Drink(aHugeCoffee)
    Else
    Drink(aHugeCoffeeToo)
    End If

    asusdk schrieb:

    Ähm bitte nicht falsch verstehen, aber habe ich irgendwo in diesem Thread erwähnt das man es nicht kann ? Nein, ich sagte ja man muss einen kleinen Umweg gehen

    Das war eigendlich so gemeint das ich immer wieder bei deinen Posts lese "Manuell ging das", "Per CodeBehind was das einfach möglich" usw.
    Und damit wollte ich dir nur sagen das du den direkten vergleich abstellen musst. Vergleiche bitte nicht zwei verschiedene Dinge miteinander. Per Binding muss man oft anders denken wie du ja schon gemerkt hast.
    Aber im Grunde eh logisch. Will ich kein Datum auswählen muss Nothing rein. also muss ich das Property auf Nothing stellen. Wenn der Datentyp dies nicht zulässt muss ich einen Datentypen nehmen der das zulässt, also NullableOf(Nothing). Schon ist alles gut. Einzig das ich dann aber wenn ich auf den Wert zugreifen will erstmal nachsehen muss ob es einen Wert gibt oder ob es Nothing ist da ja schon eine NullReferenceException geworfen wird. Klar auch.

    asusdk schrieb:

    daher versuche ich mich ja gerade in all den übungen

    Das ist ja auch gut so, nur weiter. Es ist nichts verwerflich wenn du nachfragst, das ist überhaupt kein Problem, verstehe aber bitte das ich mitlerweile etwas genervt reagiere wenn hier dann immer wieder die oben genannten Sätze von dir kommen. Äpfel mit Birnen vegleichen bringt eben nichts.

    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. ##

    verstehe aber bitte das ich mitlerweile etwas genervt reagiere wenn hier dann immer wieder die oben genannten Sätze von dir kommen

    Dahingehend bitte ich vielmals um Verzeihung, ich versuche derartige Sätze künftig zu vermeiden, ich wollte damit eigentlich nur ausdrücken, das ich beim manuellen wusste wie es geht, kam vermutlich falsch rüber.
    Ich bitte dich mir das nochmal durchgehen zu lassen ;) Ich stelle es ab ^^
    If Energy = Low Then
    Drink(aHugeCoffee)
    Else
    Drink(aHugeCoffeeToo)
    End If
    Kein problem, lass dich einfach drauf ein. Mittlerweile wirst du eh schon besser. Aber leider ist es sich er auch schwer für dich weil ein paar Grundlagen der Sprache einfach fehlen. Ich denke Nullable(Of Type) kanntest du z.b. ger nicht. Insofern ist es natürlich schwer bei sowas dann drauf zu kommen. Hier empfehle ich wirklich einfach Google zu beutzen, da findet man in Sekunden Anworten auf solche Fragen.

    Beispiel: vb.net date auf nothing setzen
    Das erste Ergebnis ist folgendes: 1. Treffer

    Paam, und schon hast du die Info, sogar inkl. der Info wie man dann auf den Wert zugreifen kann. Und das in 5 Sekunden.

    Jetzt denkst du sicher - ach gott, wenn ich das könnte müsste ich hier nicht Fragen, was denkt der sich. Tja, ich möchte versuchen jedem beizubringen sich Infos und Hilfestellung selbst zu besorgen, nicht weil ich nicht Antworten möchte sondern einfach damit IHR nicht immer so lange warten müsst bis es weitergeht. Man möchte ja schnell ans Ziel kommen und ein Erfolgserlebnis zu haben.

    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. ##

    Ja da hast du vollkommen Recht, in allen Punkten, mir war bis zu diesem thread gar nicht klar, das man Nullbare Datentypen machen kann, ich dachte immer dies müssten das Nativ unterstützen ^^ Ich sollte woll etwas mehr googlen. Danke dir
    If Energy = Low Then
    Drink(aHugeCoffee)
    Else
    Drink(aHugeCoffeeToo)
    End If
    naja - jetzt brauchst du nicht googeln - zumindest ein Beispiel hast du in meim Sample.
    Oder in NoFears Snippets. Wobei ich mit eim Binding arbeite, während NoFear ein MenuClick verwendet, um das jeweilige Datum auf Nothing zu setzen.

    (Ähm - googlen ist auch nicht schlecht, weil ich hoffe, mein Sample wirft die eine oder andere Frage auf.)
    Das ist richtig. In diesem Fall kann man mit nem EventHandler arbeiten weil es ja sowieso kein MVVM ist. Also ist das nicht verkehrt. Ich könnte ja auch einen Command an das MenuItem binden, kommt auf selbe raus.

    Ich finds nur intuitiver mit dem Contexmenü, aber das ist eben auch Geschmackssache.

    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. ##

    naja - jetzt brauchst du nicht googeln - zumindest ein Beispiel hast du in meim Sample. Oder in NoFears Snippets. Wobei ich mit eim Binding arbeite, während NoFear ein MenuClick verwendet, um das jeweilige Datum auf Nothing zu setzen.

    Ne,ne, das mit dem googeln meinte ich allgemein, nicht auf das aktuelle bezogen =)


    Das ist richtig. In diesem Fall kann man mit nem EventHandler arbeiten weil es ja sowieso kein MVVM ist. Also ist das nicht verkehrt. Ich könnte ja auch einen Command an das MenuItem binden, kommt auf selbe raus. Ich finds nur intuitiver mit dem Contexmenü, aber das ist eben auch Geschmackssache.

    naja ich denke mal das kann ich doch gleich mal als übung für Commands verwenden oder =) Muss ich ja eh lernen wenn ich weiterkommen will ^^
    If Energy = Low Then
    Drink(aHugeCoffee)
    Else
    Drink(aHugeCoffeeToo)
    End If
    Aber bei dem Kapitel bist du eben noch nicht, und deshalb will ich dich nun auch nicht unnötig verwirren.

    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. ##