版权声明:本文为博主原创文章,转载请保留原文链接。联系邮箱:[email protected] https://blog.csdn.net/Liwuqingxin/article/details/84530591
问题背景:
某一天,我想做一个签到打卡的日历。基于 Calendar,想实现这个目标,于是找到了它的 SelectedDates 属性,用于标记签到过的日期。
那么 问题 来了:
基于MVVM模式,想将其在xaml中绑定到ViewModel中的一个List<DateTime>属性。但 SelectedDates 是只读的 CLR 属性。
解决思路:
给它搭个桥:创建一个相同Type的附加属性,用附加属性绑定到ViewModel中的List<DateTime>属性。并在附加属性的变更通知和集合变更通知中添加处理:进行操作的桥接,将集合对象、集合的变动传递到SelectedDates中即可。
主要代码如下:(PS:初步使用,如果有其他问题请指教:e-mal:[email protected])
// 用于绑定(传递工具)的依赖属性
public static List<DateTime> GetSelectedDatesSource(DependencyObject obj)
{
return (List<DateTime>)obj.GetValue(SelectedDatesSourceProperty);
}
public static void SetSelectedDatesSource(DependencyObject obj, List<DateTime> value)
{
obj.SetValue(SelectedDatesSourceProperty, value);
}
public static readonly DependencyProperty SelectedDatesSourceProperty =
DependencyProperty.RegisterAttached("SelectedDatesSource", typeof(List<DateTime>), typeof(CalendarEx), new PropertyMetadata(null, SetSelectedDatesSourcePropertyChangedCallback));
// 依赖属性变更通知(集合对象的变更)
private static void SetSelectedDatesSourcePropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs args)
{
// 附加属性应用于 Calendar
Calendar calendar = d as Calendar;
if (calendar == null) return;
// 变更 SelectedDatesSource 对象,先获取新集合对象的集合内容
List<DateTime> newValue = args.NewValue as List<DateTime>;
if (newValue == null) return;
// 应用新内容
calendar.SelectedDates.Clear();
newValue.ForEach(v => calendar.SelectedDates.Add(v));
// 获取 SelectedDatesSource 对象,添加集合变更通知处理,在其中处理目标集合对象
List<DateTime> sourceCollection = GetSelectedDatesSource(d);
if (sourceCollection == null) return;
calendar.SelectedDates.CollectionChanged -= SelectedDatesOnCollectionChanged;
calendar.SelectedDates.CollectionChanged += SelectedDatesOnCollectionChanged;
}
// 集合变更通知(集合内容的变更)
private static void SelectedDatesOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs args)
{
SelectedDatesCollection collection = sender as SelectedDatesCollection;
if (collection == null) return;
switch (args.Action)
{
case NotifyCollectionChangedAction.Add:
foreach (DateTime item in args.NewItems)
{
collection.Add(item);
}
break;
case NotifyCollectionChangedAction.Remove:
foreach (DateTime item in args.NewItems)
{
collection.Remove(item);
}
break;
case NotifyCollectionChangedAction.Replace:
foreach (DateTime item in args.OldItems)
{
collection.Remove(item);
}
foreach (DateTime item in args.NewItems)
{
collection.Add(item);
}
break;
case NotifyCollectionChangedAction.Move:
// ignored
break;
case NotifyCollectionChangedAction.Reset:
// ignored
break;
default:
break;
}
}
使用起来就简单了: