Calender Control, SelectionMode=MultiplyRange

  • WPF

Es gibt 26 Antworten in diesem Thema. Der letzte Beitrag () ist von MichaHo.

    Calender Control, SelectionMode=MultiplyRange

    Hi,
    ich hab in meinem Programm ein Calender Control, dieses hat denSelectionMode auf MultiplyRange.
    Das SelectedDate ist ans ViewModel gebunden (klappt auch bestens).
    Da man nicht direkt an SelectedDates binden kann, habe ich im ViewModel eine ObservableCollection<DateTime> erstellt und im Setter der SelectedDate Property füge ich der Collection den Eintrag hinzu.
    Leider scheint das nicht zu klappen und ich sehe nicht, warum...

    Das Calender Control:

    XML-Quellcode

    1. <StackPanel Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="10">
    2. <Label Content="Datum wählen (Mehrfachauswahl):"
    3. Foreground="{DynamicResource DarkBrush}"
    4. FontSize="{StaticResource FontSizeAverage}"
    5. FontFamily="{StaticResource DefaultBold}"/>
    6. <Calendar SelectionMode="MultipleRange"
    7. SelectedDate="{Binding SelectedDate, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
    8. VerticalAlignment="Center"
    9. HorizontalAlignment="Left"/>
    10. </StackPanel>


    die beiden Properties dazu:

    C#-Quellcode

    1. private DateTime _selectedDate;
    2. public DateTime SelectedDate
    3. {
    4. get => _selectedDate;
    5. set
    6. {
    7. if(value != _selectedDate)
    8. {
    9. _selectedDate = value;
    10. OnPropertyChanged();
    11. AddSelectedDate();
    12. }
    13. }
    14. }
    15. private ObservableCollection<DateTime> _selectedDates = new ObservableCollection<DateTime>();


    und die dazugehörige Methode AddSelectedDate:

    C#-Quellcode

    1. private void AddSelectedDate()
    2. {
    3. _selectedDates.Add(_selectedDate);
    4. }


    was mach ich denn schon wieder falsch?
    Danke Euch
    "Hier könnte Ihre Werbung stehen..."
    Hallo

    Ja, das ist ein Problem. SelectedDates ist ein ReadOnly Property.

    Zwei Möglichkeiten:

    Du behandelst die relevanten dinge per CodeBehind was nun nicht unbedingt das MVVM Pattern verletzt solange der Code nur die View betrifft um die Auflistung zu "syncen" ODER und das wäre die schönere Methode du erstellst dir ein Attached Property welches dir das ganze abnimmt und du somit dann genz normal binden kannst.

    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,

    Danke Dir. Hab eben gerade auch schon festgestellt, das das SelectedDatesEvent feuert, kommt aber im ViewModel ja nicht an.
    Attached Property hab ich dran gedacht... werd mich mal dran setzen.

    Ich brauche die SelectedDates im ViewModel da diese in die DB geschrieben werden.
    "Hier könnte Ihre Werbung stehen..."

    MichaHo schrieb:

    Hab eben gerade auch schon festgestellt, das das SelectedDatesEvent feuert

    Genau. Wenn du ein Attached Property erstellst kannst du dieses Event abbonieren und dazu verwenden dein Property (ja auch ne Auflistung) hier zu syncronisieren und auf dieses dann binden zu können.

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

    Die Codebehind-Variante wäre vermutlich:

    VB.NET-Quellcode

    1. Private _selectedDates As ObservableCollection(Of DateTime) = New ObservableCollection(Of DateTime)
    2. Private Sub Calendar_SelectedDatesChanged(sender As Object, e As SelectionChangedEventArgs)
    3. _selectedDates = cal.SelectedDates
    4. End Sub


    wo würdet ihr (wenn die frage erlaubt ist) denn hier ein DP-Prop einbauen, ins "Page"-ViewModel oder wie ?

    Edit: meinte natürlich Attached-Prop ^^
    If Energy = Low Then
    Drink(aHugeCoffee)
    Else
    Drink(aHugeCoffeeToo)
    End If
    Hallo @asusdk

    Kein Dependency Property sondern ein Attached Property. Ist wieder was anderes. Siehe meine Tutorialreihe. ;)

    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,
    also so ganz steig ich noch nicht hinter.
    Ich versuchs mal in meinen Worten zu erklären.
    Ich habe also eine HelperKlasse (oder AttachedProperties oder whatever).

    C#-Quellcode

    1. public class CalendarSelectedDatesHelper : Calendar


    da ich das ja nur für den Calender brauche hab ich es von Calender abgeleitet.
    So, dann hab ich ertsmal einen Konstructor gebaut, der einen Calender annimmt um bei den statischen Methoden an den Sender oder Dependency Object ran zu kommen.

    C#-Quellcode

    1. private Calendar _cal;
    2. public CalendarSelectedDatesHelper(Calendar cal)
    3. {
    4. _cal = cal;
    5. _cal.SelectedDatesChanged += _cal_SelectedDatesChanged;
    6. }

    dann über das VS Snippet propa eine Attached Property erstellt.
    Bei der Property ist es ja so, das ich als Typ das angeben muss, was dort rein kommt, richtig? Da ich an eine ObservableCollection<DateTime> binde, hab ich dies als Typ genommen.
    Im Callback hab ich eine Methode eingetragen.

    C#-Quellcode

    1. public static ObservableCollection<DateTime> GetSelectedDates(DependencyObject obj)
    2. {
    3. return (ObservableCollection<DateTime>)obj.GetValue(SelectedDatesProperty);
    4. }
    5. public static void SetSelectedDates(DependencyObject obj, ObservableCollection<DateTime> value)
    6. {
    7. obj.SetValue(SelectedDatesProperty, value);
    8. }
    9. // Using a DependencyProperty as the backing store for SelectedDates. This enables animation, styling, binding, etc...
    10. public static readonly DependencyProperty SelectedDatesProperty =
    11. DependencyProperty.RegisterAttached("SelectedDates", typeof(ObservableCollection<DateTime>), typeof(CalendarSelectedDatesHelper), new PropertyMetadata(null,OnSelectedDatesPropertyChanged));


    dann, wenn OnSelectedDatesPropertyChanged eintritt, caste ich erstmal das DP Object in einen Calender, prüfe dann ob es überhaupt einen Calender gibt
    und erstelle dann eine Instanz meiner Helperklasse mit dem Calender.Dann rufe ich die Methode UpdateSelectedDates auf die als Parameter die Datumse benötigt, die ich mir über GetSelectedDates vom DP Object hole.

    C#-Quellcode

    1. private static void OnSelectedDatesPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    2. {
    3. var cal = d as Calendar;
    4. if(cal != null)
    5. {
    6. var helper = new CalendarSelectedDatesHelper(cal);
    7. helper.UpdateSelectedDates(GetSelectedDates(d));
    8. }
    9. }
    10. private void UpdateSelectedDates(ObservableCollection<DateTime> dates)
    11. {
    12. if (dates != null)
    13. {
    14. foreach (var date in dates)
    15. {
    16. _cal.SelectedDates.Add(date);
    17. }
    18. }
    19. }


    da ich im Konstruktor das SelectedDatesChanged Event abboniert habe, muss ich die Methode auch noch behandeln.
    Dort setze ich einfach nur die SelectedDates vom Sender

    C#-Quellcode

    1. private void _cal_SelectedDatesChanged(object sender, SelectionChangedEventArgs e)
    2. {
    3. SetSelectedDates(_cal, _cal.SelectedDates);
    4. }


    ich hab irgendwo eine Denkblokade, denn mein Property im ViewModel ist immer leer (Count = 0).

    hier noch das Xaml:

    XML-Quellcode

    1. <Calendar SelectionMode="MultipleRange"
    2. SelectedDate="{Binding SelectedDate, Mode=TwoWay}"
    3. local:CalendarSelectedDatesHelper.SelectedDates="{Binding SelectedDates}"
    4. VerticalAlignment="Center"
    5. HorizontalAlignment="Left"/>


    kann mir jemand nen schubs in die richtige Richtung geben?
    "Hier könnte Ihre Werbung stehen..."
    Ich hab glaub zu viel rum überlegt.
    Hab meine AttachedPropertie jetzt nochmal angepasst da ich bei MS gelesen habe das SelectedDates eine List<DateTime> ist:

    C#-Quellcode

    1. public class CalendarSelectedDatesHelper
    2. {
    3. public static List<DateTime> GetSelectedDates(DependencyObject obj)
    4. {
    5. return (List<DateTime>)obj.GetValue(SelectedDatesProperty);
    6. }
    7. public static void SetSelectedDates(DependencyObject obj, List<DateTime> value)
    8. {
    9. obj.SetValue(SelectedDatesProperty, value);
    10. }
    11. // Using a DependencyProperty as the backing store for SelectedDates. This enables animation, styling, binding, etc...
    12. public static readonly DependencyProperty SelectedDatesProperty =
    13. DependencyProperty.RegisterAttached("SelectedDates", typeof(List<DateTime>), typeof(CalendarSelectedDatesHelper), new PropertyMetadata(null, OnSelectedDatesChanged));
    14. private static void OnSelectedDatesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    15. {
    16. var cal = d as Calendar;
    17. var dates = (List<DateTime>)e.NewValue;
    18. foreach (var date in dates)
    19. {
    20. cal.SelectedDates.Add(date);
    21. }
    22. }
    23. }


    Eigentlich sollte es das sein und die ObservableCollection<Datetime> sollte damit gefüllt werden.
    Aber weder mit der obigen Variante, noch mit dieser wird sie gefüllt. die Collection bleibt einfach leer.
    "Hier könnte Ihre Werbung stehen..."
    hm muss leider zugeben, das ich trotz des Tutorials zu den Attached-Propertys inkl. 2 maligem gucken des Videos und nun gut 2 Stunden rumprobieren, leider auch nicht dahinter komme wie dies zu realisieren wäre, aber ich würde fast wetten das es so eine typische "sehe den Wald vor lauter Bäumen nicht"-Sache ist
    If Energy = Low Then
    Drink(aHugeCoffee)
    Else
    Drink(aHugeCoffeeToo)
    End If
    @asusdk Danke Dir fürs probieren.
    ich hab auch schon mit verschiedenen Typen probiert ObservableCollection, List und SelectedDatesCollection.
    der Debugger springt auch brav ins AP aber die SelectedDates sind immer leer.
    ich hab für heute auch aufgegeben.
    wenns garnicht geht muss CodeBehind herhalten.
    "Hier könnte Ihre Werbung stehen..."
    Hi,
    ich hab nun mal ein Sample gebaut.
    Im sample gibt es lediglich ein Control, dort drauf ist der Kalender, mit SelectionMode auf MultipleRange.
    Dann hab ich 2 AttachedProperties, einmal CalendarAttachedProperties.SelectedDatesShort und einmal CalendarAttachedProperties.SelectedDatesLong
    ist eben einmal ein normales Attached Property und einmal etwas ausführlicher.
    Dann hab ich noch einen Textblock ans SelectedDate gebunden => klappt.
    Und 3 Listboxen.
    die erste, unterhalb des Kalenders wird direkt über CodeBehind gefüllt (über das SelectedDatesChanged Event) => klappt
    die 2. ist an das ViewModel gebunden, dort an SelectedDates und soll über das AttachedProperty gefüllt werden => klappt nicht
    die 3. ist direkt an den Kalender gebunden über ElementName und dem Path=SelectedDates => klappt

    Mehr ist im Sample nicht drin. (paar Styles und Basisklassen).

    Ich komm nicht dahinter warum das AttachedProperty nicht greift.
    Dateien
    "Hier könnte Ihre Werbung stehen..."
    Ich weiss nicht ob ich das Sample verwenden könnte, da ja leider C# aber mein VS macht das Projekt auch nicht auf, mit der Meldung, das es nicht geladen werden konnte, (bereits 2 x gedownloadet falls da was schief ging) daher vermute ich eine defekte Zip-Datei
    If Energy = Low Then
    Drink(aHugeCoffee)
    Else
    Drink(aHugeCoffeeToo)
    End If
    Auch hier VS2019 Win10 aber wie in den Screenshots zu sehen , will es nicht ...
    Bilder
    • 1.JPG

      28,77 kB, 1.023×532, 85 mal angesehen
    • 2.JPG

      73,95 kB, 1.737×872, 85 mal angesehen
    If Energy = Low Then
    Drink(aHugeCoffee)
    Else
    Drink(aHugeCoffeeToo)
    End If
    ah, ok...
    könnte aber auch gut sein das du etwas warten musst, wenn du das zip entpackt hast.
    OneDrive schiebt ja erst alles in die Wolke und wenn der Haken grün ist, ist alles hoch geladen, das kann sich it dem Starten schon mal beißen.
    Bin mittlerweile einen anderen Weg gegangen. Hab das SelectedDatesCahnged Event aboniert und dort über:

    C#-Quellcode

    1. Calendar cal = sender as Calendar
    2. (DataContext as MeinViewModel).SelectedDates = cal.SelectedDates;


    meine ObservableCollection gefüllt.
    Ich denke mein Problem ist, das der Kalender nicht mitbekommt, das ich die selektierten Datumse in meinem ViewModel haben will, denn die Collection wird ausschließlich vom Kalender befüllt, nicht im Viewmodel oder sonstwo.
    "Hier könnte Ihre Werbung stehen..."
    Ich bin mir nicht sicher ob ich links zu einer Drittanbieterseite posten darf, wenn nicht bitte entfernen, dann sorry !

    ich hab im netz etwas gefunden was evtl. nützlich sein könnte Ich bin ein Link

    wobei ich mir nicht ganz sicher bin ob ich da auf nem Holzweg bin, da ich höchste schwierigkeiten habe dem Projekt zu folgen insbesondere weil alles C#
    If Energy = Low Then
    Drink(aHugeCoffee)
    Else
    Drink(aHugeCoffeeToo)
    End If
    @asusdk

    Nofear23m schrieb:

    Kein Dependency Property sondern ein Attached Property.


    Und C# Code kann man problemlos durch einen Konverter jagen um ihn dann zu verstehen.
    Rechtschreibfehler betonen den künstlerischen Charakter des Autors.