Получатель / установщик DependencyProperty не вызывается - PullRequest
4 голосов
/ 03 февраля 2012

Я пытаюсь создать пользовательский элемент управления, полученный из стандартной таблицы. Я добавил ObservableCollection в качестве DependencyProperty пользовательского элемента управления. Тем не менее, получить / установить его никогда не достигается. Могу ли я иметь некоторые рекомендации по созданию DependencyProperty, который правильно работает с ObservableCollection?

public class MyGrid : Grid
{
    public ObservableCollection<string> Items
    {
        get
        {
            return (ObservableCollection<string>)GetValue(ItemsProperty);
        }
        set
        {
            SetValue(ItemsProperty, value);
        }
    }

public static  DependencyProperty ItemsProperty =
                DependencyProperty.Register("Items", typeof(ObservableCollection<string>), 
        typeof(MyGrid), new UIPropertyMetadata(null, OnItemsChanged));

}

Ответы [ 2 ]

10 голосов
/ 03 февраля 2012

Я бы предложил не использовать ObservableCollection в качестве типа Items свойства зависимости.

Причина наличия ObservableCollection здесь (я полагаю) состоит в том, чтобы позволить UserControl подключать обработчик CollectionChanged, когда назначено значение свойства. Но ObservableCollection слишком конкретен.

Подход в WPF (например, в ItemsControl.ItemsSource ) заключается в определении базового типа интерфейса (например, IEnumerable), и когда свойству присваивается значение, выясняется, реализует ли коллекция значений определенные более конкретные интерфейсы. Это будет, по крайней мере, INotifyCollectionChanged здесь, но коллекция может также реализовать ICollectionView и INotifyPropertyChanged . Все эти интерфейсы не будут обязательными, и это позволит вашему свойству зависимости связываться со всеми видами коллекций, начиная с простого массива и заканчивая сложным ItemCollection .

Ваш обратный вызов изменения свойства OnItemsChanged будет выглядеть следующим образом:

private static void OnItemsChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
    MyGrid grid = obj as MyGrid;

    if (grid != null)
    {
        var oldCollectionChanged = e.OldValue as INotifyCollectionChanged;
        var newCollectionChanged = e.NewValue as INotifyCollectionChanged;

        if (oldCollectionChanged != null)
        {
            oldCollectionChanged.CollectionChanged -= grid.OnItemsCollectionChanged;
        }

        if (newCollectionChanged != null)
        {
            newCollectionChanged.CollectionChanged += grid.OnItemsCollectionChanged;

            // in addition to adding a CollectionChanged handler
            // any already existing collection elements should be processed here
        }
    }
}

private void OnItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    // handle collection changes here
}
4 голосов
/ 03 февраля 2012

Механизм связывания WPF может обойти ваше стандартное свойство CLR и перейти непосредственно к методам доступа к свойству зависимостей (GetValue и SetValue).

Именно поэтому логику следует размещать не внутри свойства CLR, а внутри измененного обработчика.

Кроме того, ObservableCollection<string> никогда не будет установлен, потому что при использовании свойств коллекции из XAML, например:

<local:MyGrid>
    <local:MyGrid.Items>
        <sys:String>First Item</sys:String>
        <sys:String>Second Item</sys:String>
    </local:MyGrid.Items>
</local:MyGrid>

На самом деле это вызов get Items, а затем вызов Add для каждого из элементов.

...