2009-10-28 32 views
10

Me gustaría vincular una lista de fechas a la propiedad BlackoutDates, pero realmente no parece posible. Especialmente en un escenario MVVM. ¿Alguien ha logrado algo como esto? ¿Hay algún buen control de calendario que funcione bien con MVVM?Cómo enlazar BlackoutDates en WPF Toolkit ¿Control de calendario?

+0

¿Qué ocurre cuando intenta unirse a BlackoutDates? ¿Estás obteniendo un error? – user200783

+0

No Blackoutdates ni siquiera es una opción ... Supongo que estoy usando el Datepicker, pero pensé que solo usaba el calendario y un cuadro de texto. – nportelli

Respuesta

16

Por su dilema DatePicker, me encontré con un corte claro utilizando las propiedades asociadas (modificado de mi uso de CommandBindings):

class AttachedProperties : DependencyObject 
{ 

    #region RegisterBlackoutDates 

    // Adds a collection of command bindings to a date picker's existing BlackoutDates collection, since the collections are immutable and can't be bound to otherwise. 
    // 
    // Usage: <DatePicker hacks:AttachedProperties.RegisterBlackoutDates="{Binding BlackoutDates}" > 

    public static DependencyProperty RegisterBlackoutDatesProperty = DependencyProperty.RegisterAttached("RegisterBlackoutDates", typeof(System.Windows.Controls.CalendarBlackoutDatesCollection), typeof(AttachedProperties), new PropertyMetadata(null, OnRegisterCommandBindingChanged)); 

    public static void SetRegisterBlackoutDates(UIElement element, System.Windows.Controls.CalendarBlackoutDatesCollection value) 
    { 
     if (element != null) 
      element.SetValue(RegisterBlackoutDatesProperty, value); 
    } 
    public static System.Windows.Controls.CalendarBlackoutDatesCollection GetRegisterBlackoutDates(UIElement element) 
    { 
     return (element != null ? (System.Windows.Controls.CalendarBlackoutDatesCollection)element.GetValue(RegisterBlackoutDatesProperty) : null); 
    } 
    private static void OnRegisterCommandBindingChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) 
    { 
     System.Windows.Controls.DatePicker element = sender as System.Windows.Controls.DatePicker; 
     if (element != null) 
     { 
      System.Windows.Controls.CalendarBlackoutDatesCollection bindings = e.NewValue as System.Windows.Controls.CalendarBlackoutDatesCollection; 
      if (bindings != null) 
      { 
       element.BlackoutDates.Clear(); 
       foreach (var dateRange in bindings) 
       { 
        element.BlackoutDates.Add(dateRange); 
       } 
      } 
     } 
    } 

    #endregion 
} 

Estoy seguro de que soy demasiado tarde para ayudarle a salir, pero es de esperar que alguien más lo encontrará útil.

+0

No ese proyecto se suspendió por el momento. Todavía no estoy seguro de entender las Propiedades adjuntas, pero pensé que era una forma de hacerlo, simplemente no sabía cómo hacerlo en ese momento. Es hora de volver al carro de WPF. – nportelli

+0

Sí, aún no estoy 100% seguro de que 'obtendré' Propiedades adjuntas, pero parece tener dos usos: 1. Una alternativa a un diccionario con clave de objeto dinámico para datos adicionales (como el objeto Canvas) o 2 .un uso similar al método de extensión de XAML. Mmm, una wiki comunitaria sobre el tema podría ser realmente interesante. –

6

Implementé el ejemplo anterior (la clase AttachedProperties). He creado una propiedad en mi modelo de vista así:

public CalendarBlackoutDatesCollection BlackoutDates 
    { 
     get 
     { 
      return _blackoutDates; 
     } 
     set 
     { 
      _blackoutDates = value; 
      this.RaisePropertyChanged(p => p.BlackoutDates); 
     } 
    } 

Este inerits ViewModel de ObservableBase:

using System; 
    using System.Collections.Generic; 
    using System.Linq; 
    using System.Text; 
    using System.ComponentModel; 
    using System.Windows.Data; 
    using System.Collections; 

    namespace MySolution 
    { 
     public abstract class ObservableBase : INotifyPropertyChanged 
     { 
      public event PropertyChangedEventHandler PropertyChanged; 

      public void RaisePropertyChanged(string propertyName) 
      { 
       if (this.PropertyChanged != null) 
       { 
        this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
       } 
      } 
     } 
    } 

Este es el XAML en la ventana que utiliza esta propiedad:

<Window x:Class="MySolution.MainWindow" 

    xmlns:local="clr-namespace:MySolution"> 
    <Grid> 
        <DatePicker x:Name="datePicker" Grid.Row="0" Height="30" 
           local:AttachedProperties.RegisterBlackoutDates="{Binding BlackoutDates}"> 
        </DatePicker> 
    </Grid> 

Ahora cuando quiero agregar BlackoutDates al calendario, llamo UpdateCalendarBlackoutDates en mi ViewModel:

private void UpdateCalendarBlackoutDates() 
    { 
     CalendarDateRange r = new CalendarDateRange(new DateTime(2010, 12, 9), new DateTime(2010, 12, 9)); 
     CalendarDateRange r2 = new CalendarDateRange(new DateTime(2010, 12, 10), new DateTime(2010, 12, 10)); 
     // Because we can't reach the real calendar from the viewmodel, and we can't create a 
     // new CalendarBlackoutDatesCollection without specifying a Calendar to 
     // the constructor, we provide a "Dummy calendar", only to satisfy 
     // the CalendarBlackoutDatesCollection... 
     // because you can't do: BlackoutDates = new CalendarBlackoutDatesCollection(). 
     Calendar dummyCal = new Calendar(); 
     BlackoutDates = new CalendarBlackoutDatesCollection(dummyCal); 
     // Add the dateranges to the BlackOutDates property 
     BlackoutDates.Add(r); 
     BlackoutDates.Add(r2); 
    } 

Esto funciona perfectamente para mí. Podría ser perfeccionado aún más cambiando el método OnRegisterCommandBindingChanged para aceptar una lista de DateRanges en lugar de un CalendarBlackoutDatesCollection, y el cambio de la propiedad a una lista como esta:

public List<CalendarDateRange> BlackoutDates 
{ 
    etc. 

pero por ahora esto funciona para mí ..

+0

Esto funcionó para mí, gracias. – dev1998

8

Aquí hay una versión mejorada de la respuesta de Matt que nos permite trabajar con BlackoutDates como con cualquier colección normal de Observable (no es necesario crear nuevas colecciones cada vez que desee cambiar las BlackoutDates). Almacenamos una lista de todos los calendarios y fechadores vinculados y dentro de su etiqueta almacenamos la colección utilizada en MVVM. Una modificación sencilla de la clase va a permitir trabajar con ObservableCollection <DateTime> si es necesario:

// Adds a collection of command bindings to a date picker's existing BlackoutDates collection, since the collections are immutable and can't be bound to otherwise. 
// Usage: <DatePicker CalendarAttachedProperties.RegisterBlackoutDates="{Binding BlackoutDates}" > 
public class CalendarAttachedProperties : DependencyObject 
{ 
    #region Attributes 

    private static readonly List<Calendar> _calendars = new List<Calendar>(); 
    private static readonly List<DatePicker> _datePickers = new List<DatePicker>(); 

    #endregion 

    #region Dependency Properties 

    public static DependencyProperty RegisterBlackoutDatesProperty = DependencyProperty.RegisterAttached("RegisterBlackoutDates", typeof(CalendarBlackoutDatesCollection), typeof(CalendarAttachedProperties), new PropertyMetadata(null, OnRegisterCommandBindingChanged)); 

    public static void SetRegisterBlackoutDates(DependencyObject d, CalendarBlackoutDatesCollection value) 
    { 
     d.SetValue(RegisterBlackoutDatesProperty, value); 
    } 

    public static CalendarBlackoutDatesCollection GetRegisterBlackoutDates(DependencyObject d) 
    { 
     return (CalendarBlackoutDatesCollection)d.GetValue(RegisterBlackoutDatesProperty); 
    } 

    #endregion 

    #region Event Handlers 

    private static void CalendarBindings_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) 
    { 
     CalendarBlackoutDatesCollection blackoutDates = sender as CalendarBlackoutDatesCollection; 

     Calendar calendar = _calendars.First(c => c.Tag == blackoutDates); 

     if (e.Action == NotifyCollectionChangedAction.Add) 
     { 
      foreach (CalendarDateRange dateRange in e.NewItems) 
      { 
       calendar.BlackoutDates.Add(dateRange); 
      } 
     } 
    } 

    private static void DatePickerBindings_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) 
    { 
     CalendarBlackoutDatesCollection blackoutDates = sender as CalendarBlackoutDatesCollection; 

     DatePicker datePicker = _datePickers.First(c => c.Tag == blackoutDates); 

     if (e.Action == NotifyCollectionChangedAction.Add) 
     { 
      foreach (CalendarDateRange dateRange in e.NewItems) 
      { 
       datePicker.BlackoutDates.Add(dateRange); 
      } 
     } 
    } 

    #endregion 

    #region Private Methods 

    private static void OnRegisterCommandBindingChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) 
    { 
     Calendar calendar = sender as Calendar; 
     if (calendar != null) 
     { 
      CalendarBlackoutDatesCollection bindings = e.NewValue as CalendarBlackoutDatesCollection; 
      if (bindings != null) 
      { 
       if (!_calendars.Contains(calendar)) 
       { 
        calendar.Tag = bindings; 
        _calendars.Add(calendar); 
       } 

       calendar.BlackoutDates.Clear(); 
       foreach (var dateRange in bindings) 
       { 
        calendar.BlackoutDates.Add(dateRange); 
       } 
       bindings.CollectionChanged += CalendarBindings_CollectionChanged; 
      } 
     } 
     else 
     { 
      DatePicker datePicker = sender as DatePicker; 
      if (datePicker != null) 
      { 
       CalendarBlackoutDatesCollection bindings = e.NewValue as CalendarBlackoutDatesCollection; 
       if (bindings != null) 
       { 
        if (!_datePickers.Contains(datePicker)) 
        { 
         datePicker.Tag = bindings; 
         _datePickers.Add(datePicker); 
        } 

        datePicker.BlackoutDates.Clear(); 
        foreach (var dateRange in bindings) 
        { 
         datePicker.BlackoutDates.Add(dateRange); 
        } 
        bindings.CollectionChanged += DatePickerBindings_CollectionChanged; 
       } 
      } 
     } 
    } 

    #endregion 
} 

Aquí es ObservableCollection < DateTime versión >:

// Adds a collection of command bindings to a date picker's existing BlackoutDates collection, since the collections are immutable and can't be bound to otherwise. 
// Usage: <DatePicker hacks:AttachedProperties.RegisterBlackoutDates="{Binding BlackoutDates}" > 
public class CalendarAttachedProperties : DependencyObject 
{ 
    #region Attributes 

    private static readonly List<Calendar> _calendars = new List<Calendar>(); 
    private static readonly List<DatePicker> _datePickers = new List<DatePicker>(); 

    #endregion 

    #region Dependency Properties 

    public static DependencyProperty RegisterBlackoutDatesProperty = DependencyProperty.RegisterAttached("RegisterBlackoutDates", typeof(ObservableCollection<DateTime>), typeof(CalendarAttachedProperties), new PropertyMetadata(null, OnRegisterCommandBindingChanged)); 

    public static void SetRegisterBlackoutDates(DependencyObject d, ObservableCollection<DateTime> value) 
    { 
     d.SetValue(RegisterBlackoutDatesProperty, value); 
    } 

    public static ObservableCollection<DateTime> GetRegisterBlackoutDates(DependencyObject d) 
    { 
     return (ObservableCollection<DateTime>)d.GetValue(RegisterBlackoutDatesProperty); 
    } 

    #endregion 

    #region Event Handlers 

    private static void CalendarBindings_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) 
    { 
     ObservableCollection<DateTime> blackoutDates = sender as ObservableCollection<DateTime>; 

     Calendar calendar = _calendars.First(c => c.Tag == blackoutDates); 

     if (e.Action == NotifyCollectionChangedAction.Add) 
     { 
      foreach (DateTime date in e.NewItems) 
      { 
       calendar.BlackoutDates.Add(new CalendarDateRange(date)); 
      } 
     } 
    } 

    private static void DatePickerBindings_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) 
    { 
     ObservableCollection<DateTime> blackoutDates = sender as ObservableCollection<DateTime>; 

     DatePicker datePicker = _datePickers.First(c => c.Tag == blackoutDates); 

     if (e.Action == NotifyCollectionChangedAction.Add) 
     { 
      foreach (DateTime date in e.NewItems) 
      { 
       datePicker.BlackoutDates.Add(new CalendarDateRange(date)); 
      } 
     } 
    } 

    #endregion 

    #region Private Methods 

    private static void OnRegisterCommandBindingChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) 
    { 
     Calendar calendar = sender as Calendar; 
     if (calendar != null) 
     { 
      ObservableCollection<DateTime> bindings = e.NewValue as ObservableCollection<DateTime>; 
      if (bindings != null) 
      { 
       if (!_calendars.Contains(calendar)) 
       { 
        calendar.Tag = bindings; 
        _calendars.Add(calendar); 
       } 

       calendar.BlackoutDates.Clear(); 
       foreach (DateTime date in bindings) 
       { 
        calendar.BlackoutDates.Add(new CalendarDateRange(date)); 
       } 
       bindings.CollectionChanged += CalendarBindings_CollectionChanged; 
      } 
     } 
     else 
     { 
      DatePicker datePicker = sender as DatePicker; 
      if (datePicker != null) 
      { 
       ObservableCollection<DateTime> bindings = e.NewValue as ObservableCollection<DateTime>; 
       if (bindings != null) 
       { 
        if (!_datePickers.Contains(datePicker)) 
        { 
         datePicker.Tag = bindings; 
         _datePickers.Add(datePicker); 
        } 

        datePicker.BlackoutDates.Clear(); 
        foreach (DateTime date in bindings) 
        { 
         datePicker.BlackoutDates.Add(new CalendarDateRange(date)); 
        } 
        bindings.CollectionChanged += DatePickerBindings_CollectionChanged; 
       } 
      } 
     } 
    } 

    #endregion 
} 
Cuestiones relacionadas