具有自定义ItemsSource依赖项属性的用户控件

时间:2010-12-27 14:43:45

标签: wpf user-controls mvvm

我有一个带有ItemsSource属性的UserControl。由于基本UserControl类没有实现ItemsSource,我必须创建自己的依赖属性,如下所示:

#region ItemsSource Dependency Property
    public static readonly DependencyProperty ItemsSourceProperty =
        DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(MonthViewControl),
        new PropertyMetadata(OnItemsSourceChanged));

    static void OnItemsSourceChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        (obj as MonthViewControl).OnItemsSourceChanged(e);
    }

    private void OnItemsSourceChanged(DependencyPropertyChangedEventArgs e)
    {
        RefreshLayout();
    }

    public IEnumerable ItemsSource
    {
        get
        {
            return (base.GetValue(ItemsSourceProperty) as IEnumerable);
        }
        set
        {
            base.SetValue(ItemsSourceProperty, value);
        }
    }

    #endregion

现在在我的ViewModel中,我有一个Events属性,它是EventItem项的ICollectionView,如下所示:

private ObservableCollection<Controls.EventCalendar.EventItem> eventItems;
    private CollectionViewSource events;
    public System.ComponentModel.ICollectionView Events
    {
        get
        {
            if (events == null)
            {
                events = new CollectionViewSource();
                events.Source = eventItems;
            }

            return events.View;
        }
    }

我面临的问题是,在我的View中,当我绑定到Events属性,并且我将一个Item添加到eventItems时,UserControl将不会触发ItemsSourceChanged事件,因此不会更新UI。 为了测试,我在视图中添加了一个简单的列表框,它也绑定到Events属性。这就像一个魅力。对eventItems observableCollection的更新反映在ListBox中。

我认为它与我的ItemsSource依赖属性有关。也许我需要使用继承表单ItemsControl而不是UserControl的自定义控件?

为了帮助您了解我的问题:我正在尝试创建一个类似控件的日历,用于显示事件/议程条目(类似于Google日历)。它就像一个魅力。调整控件大小时更新UI。唯一剩下的就是ItemsSource更改后的自动更新。

希望有人可以提供帮助。

编辑:我发布的那一刻我意识到事件无法触发,因为ItemsSource属性不会更改。它是基础集合的变化。但是,我不是那样处理的。我需要实现什么才能使其工作。只是暗示就足够了。我不需要每个实现细节。

1 个答案:

答案 0 :(得分:6)

在Reflector中打开PresentationFramework.dll并查看System.Windows.Controls.ItemsControl,显示以下内容:

public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register("ItemsSource", typeof(IEnumerable), 
   typeof(ItemsControl), new FrameworkPropertyMetadata(null, 
   new PropertyChangedCallback(ItemsControl.OnItemsSourceChanged)));

private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    ItemsControl control = (ItemsControl) d;
    IEnumerable oldValue = (IEnumerable) e.OldValue;
    IEnumerable newValue = (IEnumerable) e.NewValue;
    ItemValueStorageField.ClearValue(d);
    if ((e.NewValue == null) && !BindingOperations.IsDataBound(d, ItemsSourceProperty))
    {
        control.Items.ClearItemsSource();
    }
    else
    {
        control.Items.SetItemsSource(newValue);
    }
    control.OnItemsSourceChanged(oldValue, newValue);
}

不知道我的预感是什么RefreshLayout它与ObservableCollection<T>被包裹的方式有关,因为上面的代码不知道具体的集合类型是什么,因此由被包裹的类型处理;在这种情况下,ObservableCollection<T>尝试修改您的属性,如下所示返回默认视图,并将ItemsSource属性调整为更类似于框架中的上述代码,并从那里向后工作。

private ObservableCollection<Controls.EventCalendar.EventItem> eventItems;
private ICollectionview eventsView;
public System.ComponentModel.ICollectionView Events
{
    get
    {
        if (eventsView == null)
            eventsView = CollectionViewSource.GetDefaultView(eventItems);
        return eventsView;
    }
}