代码之家  ›  专栏  ›  技术社区  ›  nportelli

如何在wpf toolkit日历控件中绑定中断日期?

  •  10
  • nportelli  · 技术社区  · 15 年前

    我想将日期列表绑定到Blackoutdates属性,但似乎不太可能。尤其是在mvvm场景中。有人做过这样的事吗?有没有好的日历控件可以很好地使用mvvm?

    3 回复  |  直到 7 年前
        1
  •  16
  •   Matt DeKrey Kiran    14 年前

    对于您的DatePicker难题,我发现了一个使用附加属性(从使用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
    }
    

    我肯定我来不及帮你了,但希望其他人会觉得有用。

        2
  •  8
  •   Ignacio Soler Garcia    13 年前

    下面是matt的答案的改进版本,它允许我们像处理任何正常的可观察集合一样处理中断日期(您不需要每次都创建新的集合来更改中断日期)。我们存储绑定的所有日历和日期选择器的列表,在它们的标记中存储mvvm中使用的集合。类的简单修改将允许在需要时使用ObservableCollection<DateTime>:

    // 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
    }
    

    这里是ObservableCollection<DateTime>版本:

    // 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
    }
    
        3
  •  6
  •   wouter4    14 年前

    我实现了上面的示例(attachedProperties类)。我在viewmodel中创建了一个属性,如下所示:

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

    此视图模型来自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));
                    }
                }
             }
         }
    

    这是窗口中使用此属性的xaml:

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

    现在,当我想向日历中添加BlackoutDates时,我在ViewModel中调用updateCalendarBrackOutDates:

        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);
        }
    

    这对我很有效。通过将onRegisterCommandBindingChanged方法更改为接受日期范围列表而不是CalendarBlackOutDatesCollection,并将属性更改为如下列表,可以进一步完善该方法:

    public List<CalendarDateRange> BlackoutDates
    {
      etc.
    

    但现在这对我很有效…