WPF:只读集合在 XAML 中的绑定(WPF:Binding for readonly collection in xaml)

版权声明:本文为博主原创文章,转载请保留原文链接。联系邮箱:[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;
    }
}

使用起来就简单了:

猜你喜欢

转载自blog.csdn.net/Liwuqingxin/article/details/84530591