Присоединенное свойство не работает, если я не помещу «Свойство» в конец его имени

#c# #wpf #attached-properties

#c# #wpf #прикрепленные свойства

Вопрос:

У меня есть простое присоединенное свойство:

 class TestAttached
{
    public static readonly DependencyProperty TestProperty = DependencyProperty.RegisterAttached("TestProperty", typeof(string), typeof(TestAttached));

    public static string GetTest(DependencyObject d)
    {
        return (string)d.GetValue(TestProperty);
    }

    public static void SetTest(DependencyObject d, string value)
    {
        d.SetValue(TestProperty, value);
        TextBox tb = d as TextBox;
        tb.Text = value;
    }
}
  

и

 <TextBox local:TestAttached.Test="Test" />
  

Ничего не происходит, и точка останова не достигнута (которую я поставил SetTest ), если я не установлю первый параметр RegisterAttached в «TestProperty» вместо «Test». Ни один учебник, который я нашел, в том числе в MSDN, не делает этого, и, насколько я могу судить, мой код такой же, как у них, и должен работать. Что дает?

Ответ №1:

Когда свойство зависимости get / set через XAML, метод-оболочка никогда не вызывается. Итак, вам следует избегать написания кода там.

Из MSDN:

Текущая реализация WPF поведения процессора XAML для настройки свойств полностью обходит обертки, вам не следует добавлять какую-либо дополнительную логику в определения набора оболочки для вашего пользовательского свойства зависимостей. Если вы добавите такую логику в определение set, то логика не будет выполняться, если свойство задано в XAML, а не в коде.

Вместо этого вы можете использовать PropertyChangedCallback , если хотите добавить какой-либо код для изменения свойства DP.

 public static readonly DependencyProperty TestProperty =
    DependencyProperty.RegisterAttached("Test", typeof(string),
                                         typeof(TestAttached),
                                         new PropertyMetadata(TestChanged));

public static void TestChanged(DependencyObject d,
                               DependencyPropertyChangedEventArgs e)
{
    // Place your code here
}
  

Обновить

Но если я изменю имя на «TestProperty», то точка останова будет достигнута при SetTest.

Причина этого в том, что Test теперь оно ведет себя как обычное свойство CLR. Свойство — это не что иное, как методы Get / Set, когда вы разбираете его до IL-кода.

Вот почему сеттер получает удар, как и для обычного свойства CLR.

Если вы попытаетесь связать с каким-либо другим свойством,

 <TextBox local:TestAttached.Test="{Binding SomeCLRProperty}" />
  

вы увидите сбои приложения с указанием:

«Привязка» не может быть установлена для свойства «SetTest» типа «TextBox». «Привязка» может быть установлена только для DependencyProperty объекта DependencyObject.

Комментарии:

1. Но если я изменю имя на «TestProperty», то точка останова будет достигнута в SetTest

2. @Aron — Нет, третий аргумент относится к типу владельца и поскольку это присоединенное свойство. Таким образом, владелец будет содержать класс. Так и должно быть typeof(TestAttached) .

3. @RohitVats не могли бы вы также записать строку TextBox tb = d as TextBox; msmvps.com/blogs/jon_skeet/archive/2013/09/19 /…

4. Я основывал это в основном на этом посте , откуда взялось большинство этого материала, но я также просто пытался создать SSCCE… Ну что ж

5. @Aron — Эта часть не имеет отношения к этому ответу, потому что OP интересуется, почему DP не работает. Casting vs "as" это совершенно другая тема. Пусть ссылка останется здесь в комментариях (очевидно, это может быть полезно для OP), чтобы ответ оставался точным для будущих читателей.