Пользовательский элемент управления с пользовательским свойством зависимости ItemsSource - PullRequest
9 голосов
/ 27 декабря 2010

У меня есть UserControl со свойством ItemsSource. Поскольку базовый класс 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, которое представляет собой ICollectionView элементов EventItem, например:

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 и, следовательно, не обновлять пользовательский интерфейс. Для тестирования я добавил простое окно списка в представление, которое также привязывается к свойству Events. Это работает как шарм. Обновления eventItems observableCollection отражаются в ListBox.

Я полагаю, что это как-то связано с моим свойством зависимости ItemsSource. Может быть, мне нужно использовать пользовательский элемент управления, который наследует форму ItemsControl вместо UserControl?

Чтобы помочь вам понять мою проблему: я пытаюсь создать календарь, похожий на элемент управления, который показывает события / записи в повестке дня (аналогично Календарю Google). Отлично работает. Пользовательский интерфейс обновляется при изменении размера элемента управления. Единственное, что осталось - это автоматическое обновление после изменения ItemsSource.

Надеюсь, кто-то может помочь.

РЕДАКТИРОВАТЬ: В момент публикации я понял, что событие не может быть запущено, поскольку свойство ItemsSource не изменяется. Это основная коллекция, которая меняется. Тем не менее, я не как справиться с этим. Что мне нужно реализовать, чтобы сделать эту работу. Достаточно только намека. Мне не нужны все детали реализации.

1 Ответ

6 голосов
/ 27 декабря 2010

Открытие PresentationFramework.dll в Reflector и просмотр 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;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...