具有自定义ItemsSource依赖项属性的用户控件 [英] User Control with custom ItemsSource dependency property

查看:116
本文介绍了具有自定义ItemsSource依赖项属性的用户控件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I've got a UserControl with an ItemsSource property. As the base UserControl class does not implement ItemsSource, I had to create my own dependency property like this:

#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,如下所示:

Now in my ViewModel I have an Events property which is an ICollectionView of EventItem items like so:

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

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

The issue I'm facing is that in my View, when I bind to the Events property, and I add an Item to eventItems, the UserControl won't fire the ItemsSourceChanged event and hence not update the UI. For the sake of testing I added a simple listbox to the view which also binds to the Events property. That works like a charm. Updates to eventItems observableCollection are reflected in the ListBox.

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

I'm figuring it has something to do with my ItemsSource dependency property. Maybe I would need to use a Custom Control which inherits form ItemsControl instead of a UserControl?

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

To help you understand my problem: I'm trying to create a calendar like control which shows events/agenda entries (similar to Google Calendar). It works like a charm. The UI is updated when the control is resized. The only thing that's left is the automagical update once the ItemsSource changes.

希望有人可以提供帮助.

Hope someone can help.

发布我的那一刻,我意识到该事件无法触发,因为ItemsSource属性没有更改.它是基础集合会发生变化.但是,我不是如何处理该问题.我需要执行什么才能使这项工作进行.只是一个提示就足够了.我不需要每个实施细节.

The moment I posted I realized that the event can't be fired as the ItemsSource property does not change. It is the underlying collection that changes. However, I'm not how to handle that. What do I need to implement to make this work. Just a hint would be enough. I don't need every implementation details.

推荐答案

在Reflector中打开PresentationFramework.dll并查看System.Windows.Controls.ItemsControl,结果如下:

Opening the PresentationFramework.dll within Reflector and looking at System.Windows.Controls.ItemsControl showed the following:

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>的包装方式有关,因为上面的代码忽略了具体的集合类型,因此将由RefreshLayout处理.包装类型;在这种情况下,ObservableCollection<T>尝试如下所示修改属性,以返回默认视图,并调整您的ItemsSource属性,使其更类似于框架中的上述代码,并从那里向后工作.

Not knowing what RefreshLayout does my hunch is that it has something to do with the way the ObservableCollection<T> is being wrapped as the above code is oblivious to what the concrete collection type is and it would therefore be handled by the type being wrapped; in this case an ObservableCollection<T> Try modifying your property as seen below to return the default view and adjust your ItemsSource property to be more akin to the above code from the framework and work backwards from there.

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

这篇关于具有自定义ItemsSource依赖项属性的用户控件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆