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

Gil*_*zzi 9 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
Run Code Online (Sandbox Code Playgroud)

现在在我的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;
        }
    }
Run Code Online (Sandbox Code Playgroud)

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

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

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

希望有人能提供帮助.

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

Aar*_*ver 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);
}
Run Code Online (Sandbox Code Playgroud)

不知道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;
    }
}
Run Code Online (Sandbox Code Playgroud)