DepencyProperty не обновляется привязкой к UserControl

Итак, я пытаюсь создать UserControl с некоторыми DependencyProperties, чтобы я мог повторно использовать код. Однако некоторые свойства не обновляются, а другие обновляются. Что еще более странно, так это то, что даже для тех свойств, которые обновляются, метод set вообще не вызывается.

Вот мой код:

На ViewModel:

public ICommand TestCommand = new DelegateCommand(x => MessageBox.Show("Ocorreu Evento"));
public List<string> TestList = new List<string> { "Hello","This","is","a","Test" };

В представлении:

<views:CustomizedList Header="Testing"
                        Items="{Binding TestList}"/>

Представление пользовательского элемента управления:

<StackPanel>
    <Label Content="{Binding Header}" />
    <ListBox ItemsSource="{Binding Items}">
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel/>
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
        <ListBox.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="Hello"/>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</StackPanel>

Код управления пользователем:

    public string Header
    {
        get { return (string)GetValue(HeaderProperty); }
        set
        {
            MessageBox.Show("New header is " + value); 
            SetValue(HeaderProperty, value);
        }
    }       

    public BindingList<object> Items
    {
        get { return (BindingList<object>)GetValue(ItemsProperty); }
        set {
            SetValue(ItemsProperty, value);
            Console.WriteLine("Value was set with " + value.Count + " items.");
        }
    }

    public static readonly DependencyProperty HeaderProperty =
        DependencyProperty.Register("Header", typeof(string),
          typeof(ListaCustomizada));

    public static readonly DependencyProperty ItemsProperty =
        DependencyProperty.Register("Items", typeof(BindingList<object>),
          typeof(ListaCustomizada));

Заголовок отображается, а элементов нет. Не то, чтобы я добавил некоторые отпечатки консоли, чтобы проверить, вызываются ли методы, но ничего не отображается, даже для заголовка. Я устанавливаю DataContext UserControl как самого себя.

Любые идеи?

ИЗМЕНИТЬ:

Следуя предложению @Garry Vass, я добавил функцию обратного вызова. Новый код:

    public static readonly DependencyProperty HeaderProperty =
        DependencyProperty.Register("Header", typeof(string),
          typeof(ListaCustomizada), new PropertyMetadata("", ChangedCallback));

    public static readonly DependencyProperty ItemsProperty =
        DependencyProperty.Register("Items", typeof(BindingList<object>),
          typeof(ListaCustomizada), new PropertyMetadata(new BindingList<object>(), ChangedCallback));

    private static void ChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        Console.WriteLine("Dependency property is now " + e.NewValue);
    }

При этом я вижу изменение значения заголовка, но для элементов не происходит обратного вызова.

ИЗМЕНИТЬ:

Изменен TestList как свойство вместо поля, его тип BindingList для согласования с данными в пользовательском элементе управления, все те же результаты.

    public BindingList<object> TestList { get; set; }

    public ViewModel()
    {
        TestList = new BindingList<object> { "Hello", "This", "is", "a", "Test" };
    }

РЕДАКТИРОВАТЬ: Тестируя больше, я обнаружил, что ошибка возникает из-за того, что DP ont eh usercontrol привязан к DP в представлении, которое привязано к виртуальной машине.

EDIT: Наконец-то заработало. Поискав немного глубже, я нашел эту ссылку < /a> в codeproject, который прекрасно объясняет, как создавать пользовательские элементы управления.


person Eduardo Bonet    schedule 02.08.2013    source источник
comment
DependencyProperties в WPF — это особый вид свойств. При этом ваши Console.WriteLine() и MessageBox.Show(), скорее всего, являются причиной. DependencyProperties не должно иметь ничего лишнего, кроме своих оригинальных геттеров и сеттеров.   -  person PoweredByOrange    schedule 02.08.2013
comment
Ну, я добавил их, заметив, что ничего не изменилось, так что они не являются основной причиной. Я удалил их и получил те же симптомы: значение заголовка отображается, а коллекция - нет. Судя по всему, это должно быть что-то с двойной привязкой (ViewModel->View->UserControl)   -  person Eduardo Bonet    schedule 02.08.2013


Ответы (1)


Хотя это может показаться нелогичным, механизм привязки WPF в основном игнорирует сеттер и геттер в вашем коде и использует свою собственную версию, которая находится глубоко внутри WPF. Таким образом, любой код, который вы поместите туда для вмешательства или, в вашем случае, для проверки, просто останется невыполненным.

Так зачем они там вообще? Они являются помощниками во время компиляции, а также дают вашему Xaml что-то, к чему можно подключиться.

Если вы хотите вмешаться или проверить, что происходит со свойством зависимости, вы можете объявить его следующим образом...

    #region MyProperty (DependencyProperty)
    public int MyProperty
    {
        get { return (int)GetValue(MyPropertyProperty); }
        set { SetValue(MyPropertyProperty, value); }
    }
    public static readonly DependencyProperty MyPropertyProperty =
        DependencyProperty.Register("MyProperty", typeof(int), typeof(MainWindow),
          new PropertyMetadata(0, ChangedCallback));
    private static void ChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        Console.WriteLine("Dependency property is now " + e.NewValue);
    }
    #endregion

Это объявляет свойство зависимости с обратным вызовом Property Changed. WPF будет вызывать его всякий раз, когда свойство установлено.

Вы увидите изменения, происходящие в методе обратного вызова, привязав отладчик к оператору Console.

person Gayot Fow    schedule 02.08.2013
comment
Я пробовал. Это работает для заголовка (я вижу, что значение изменилось), но, как я подозревал, обратный вызов для свойства Items вообще не вызывается. - person Eduardo Bonet; 02.08.2013
comment
Ваш «TestList» должен быть СОБСТВЕННОСТЬЮ с общедоступным геттером и сеттером. Вы инициализируете его как поле. Создайте свойство и инициализируйте его в конструкторе вашей виртуальной машины. Кроме того, людям нравится использовать ObservableCollection вместо List, но это все равно должно быть СВОЙСТВОМ, если вы хотите привязать - person Gayot Fow; 02.08.2013
comment
Добавил {get;set;} для TestList, изменил тип на BindingList‹object›, по-прежнему получая те же результаты. - person Eduardo Bonet; 02.08.2013
comment
Я вижу это сейчас. Это связано с вашей виртуальной машиной! Где устанавливается DC для главного окна? - person Gayot Fow; 02.08.2013
comment
Думаю, с ВМ тоже все в порядке. Я просто копирую и вставляю важные части, но вскоре после того, как я установил контекст данных представления (который является пользовательским элементом управления) для виртуальной машины. Все привязки работают между VM/V, проблема в переходе VM->V->UC - person Eduardo Bonet; 02.08.2013
comment
Да, я пытаюсь здесь, и ошибка возникает из-за того, что я привязываюсь к свойству, значение которого также привязано, т.е. е. v0=hi -> v1={Привязка v0} -> v2 = {Привязка v1}. В этом случае v1 получает правильное значение, а v2 — нет. - person Eduardo Bonet; 02.08.2013