开发者

User Control with custom ItemsSource dependency property

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

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

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.

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?

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.

EDIT: 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.


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

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜