Поделиться через


Общие сведения о присоединенных свойствах

Присоединенное свойство — это концепция языка разметки приложений Extensible Application Markup Language (XAML). Присоединенные свойства позволяют задавать дополнительные пары свойств и значений для любого элемента XAML, наследуемого от DependencyObjectэлемента, даже если элемент не определяет эти дополнительные свойства в объектной модели. Дополнительные свойства доступны глобально. Присоединенные свойства обычно определяются как специализированная форма свойства зависимостей, которая не имеет обычной оболочки свойств.

Предпосылки

В статье предполагается, что у вас есть базовые знания о свойствах зависимости и что вы прочитали Обзор свойств зависимостей. Чтобы следовать примерам в этой статье, это поможет вам, если вы знакомы с XAML и знаете, как писать приложения Windows Presentation Foundation (WPF).

Почему используют присоединенные свойства

Присоединенное свойство позволяет дочернему элементу указать уникальное значение для свойства, определенного в родительском элементе. Распространенный сценарий — это дочерний элемент, указывающий, как он должен быть отображен в пользовательском интерфейсе его родительским элементом. Например, DockPanel.Dock — это присоединенное свойство, так как оно задано для дочерних элементов DockPanel, а не для самого DockPanel. Класс DockPanel определяет статическое DependencyProperty поле с именем DockProperty, а затем предоставляет GetDock и SetDock методы в качестве общедоступных методов доступа для присоединенного свойства.

Присоединенные свойства в XAML

В XAML вы задаете присоединенные свойства с помощью синтаксиса <attached property provider type>.<property name>, где присоединенный поставщик свойств является классом, определяющим присоединенное свойство. В следующем примере показано, как дочерний DockPanel элемент может задать DockPanel.Dock значение свойства.

<DockPanel>
    <TextBox DockPanel.Dock="Top">Enter text</TextBox>
</DockPanel>

Использование аналогично статическому свойству, которое ссылается на тип, принадлежащий и регистрирующий присоединенное свойство (например, DockPanel), а не имя экземпляра.

При указании присоединенного свойства с помощью атрибута XAML применяется только действие набора. Вы не можете напрямую получить значение свойства через XAML, хотя существуют некоторые косвенные механизмы сравнения значений, таких как триггеры в стилях.

Присоединенные свойства в WPF

Присоединенные свойства — это концепция XAML, свойства зависимостей — это концепция WPF. В WPF большинство присоединенных к пользовательскому интерфейсу свойств в типах WPF реализуются как свойства зависимостей. Присоединенные свойства WPF, реализованные в качестве свойств зависимостей, поддерживают понятия свойств зависимостей, такие как метаданные свойств, включая значения по умолчанию из метаданных.

Модели использования присоединенных свойств

Хотя любой объект может задать значение присоединенного свойства, то это не означает, что установка значения приведет к существенному результату или значение будет использоваться другим объектом. Основной целью присоединенных свойств является предоставление объектов из широкого спектра иерархий классов и логических связей для предоставления общих сведений типу, определяющему присоединенное свойство. Использование присоединенного свойства обычно осуществляется по одной из следующих моделей:

  • Тип, определяющий присоединенное свойство, является родительским элементом элементов, которые задают значения для присоединенного свойства. Родительский тип выполняет итерацию дочерних объектов с помощью внутренней логики, которая действует в структуре дерева объектов, получает значения и действует на эти значения каким-то образом.
  • Тип, определяющий присоединенное свойство, используется в качестве дочернего элемента для различных возможных родительских элементов и моделей содержимого.
  • Тип, определяющий присоединенное свойство, представляет службу. Другие типы задают значения для присоединенного свойства. Затем, когда элемент, который задает свойство, оценивается в контексте службы, присоединенные значения свойств получаются с помощью внутренней логики класса службы.

Пример определяемого родителем присоединенного свойства

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

DockPanel определяет присоединенное DockPanel.Dock свойство. DockPanel имеет код уровня класса, в частности MeasureOverride и ArrangeOverride, которые являются частью его логики отрисовки. Экземпляр DockPanel проверяет, установлено ли значение для DockPanel.Dock любым из его непосредственных дочерних элементов. Если да, эти значения становятся входными данными в логику отрисовки, примененную к каждому дочернему элементу. Хотя теоретически присоединенные свойства могут влиять на элементы за пределами непосредственного родительского элемента, определенное поведение для вложенного DockPanel экземпляра заключается только в взаимодействии с его непосредственной дочерней коллекцией элементов. Таким образом, если вы установили DockPanel.Dock на элемент, не имеющий DockPanel родителя, никакой ошибки или исключения не будет вызвано, и вы создадите глобальное значение свойства, которое не будет использовано ни одним DockPanel.

Присоединенные свойства в коде

Присоединенные свойства в WPF не имеют типичных методов CLR get и set оболочки, так как свойства могут быть заданы вне пространства имен CLR. Чтобы разрешить обработчику XAML задать эти значения при анализе XAML, класс, определяющий присоединенное свойство, должен реализовать выделенные методы доступа в виде Get<property name> и Set<property name>.

Вы также можете использовать выделенные методы доступа для получения и задания присоединенного свойства в коде, как показано в следующем примере. В этом примере myTextBox является экземпляром класса TextBox.

DockPanel myDockPanel = new();
TextBox myTextBox = new();
myTextBox.Text = "Enter text";

// Add child element to the DockPanel.
myDockPanel.Children.Add(myTextBox);

// Set the attached property value.
DockPanel.SetDock(myTextBox, Dock.Top);
Dim myDockPanel As DockPanel = New DockPanel()
Dim myTextBox As TextBox = New TextBox()
myTextBox.Text = "Enter text"

' Add child element to the DockPanel.
myDockPanel.Children.Add(myTextBox)

' Set the attached property value.
DockPanel.SetDock(myTextBox, Dock.Top)

Если вы не добавите myTextBox в качестве дочернего элемента myDockPanel, вызов SetDock не вызовет исключения и не будет иметь никакого эффекта. Только значение DockPanel.Dock, заданное в дочернем элементе DockPanel, может повлиять на отрисовку, и отрисовка будет одинаковой независимо от того, задано ли значение перед или после добавления дочернего элемента в DockPanel.

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

Метаданные присоединенного свойства

Метаданные для присоединенного свойства обычно не отличаются от свойства зависимостей. При регистрации присоединенного свойства используйте FrameworkPropertyMetadata для указания характеристик свойства, например, влияет ли свойство на отрисовку или измерение. При указании значения по умолчанию путем переопределения метаданных присоединенного свойства это значение становится значением по умолчанию для неявного присоединенного свойства в экземплярах переопределяющего класса. Если значение присоединенного свойства не задано в противном случае, значение по умолчанию сообщается, когда свойство запрашивается с помощью Get<property name> метода доступа с экземпляром класса, в котором вы указали метаданные.

Чтобы включить наследование значений свойств для свойства, используйте присоединенные свойства вместо не присоединенных свойств зависимостей. Дополнительные сведения см. в разделе «Наследование значений свойств».

Настраиваемые присоединенные свойства

Когда создавать присоединенное свойство

Создание присоединенного свойства полезно при следующих случаях:

  • Вам нужен механизм настройки свойства, доступный для классов, отличных от определяющего класса. Распространенный сценарий — это макет пользовательского интерфейса, например DockPanel.Dock, Panel.ZIndex и Canvas.Top — все это примеры существующих свойств макета. В сценарии макета дочерние элементы элемента управления макетом могут выразить требования к макету родительскому элементу макета и задать значение для присоединенного свойства, определенного родительским элементом.

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

  • Вам нужна поддержка конструктора WPF Visual Studio, например возможность редактирования свойства в окне "Свойства ". Дополнительные сведения см. в разделе "Обзор разработки элементов управления"

  • Вы хотите использовать наследование значений свойств.

Как создать присоединенное свойство

Если класс определяет присоединенное свойство исключительно для использования другими типами, класс не должен быть производным от DependencyObject. В противном случае следуйте модели WPF наличия присоединенного свойства, которое также является свойством зависимости, производя свой класс от DependencyObject.

Определите присоединенное свойство как зависимость в определяемом public static readonly классе, объявив поле типа DependencyProperty. Затем назначьте возвращаемое значение RegisterAttached метода полю, которое также называется идентификатором свойства зависимостей. Следуйте соглашению об именовании свойств WPF, которое отличает поля от свойств, которые они представляют, именуя поле <property name>Propertyидентификатора. Кроме того, предоставьте статические Get<property name> и Set<property name> методы доступа, которые позволяют системе свойств получить доступ к присоединенному свойству.

В следующем примере показано, как зарегистрировать свойство зависимостей с помощью RegisterAttached метода и как определить методы доступа. В примере имя присоединенного свойства — HasFish, поэтому поле идентификатора называется HasFishProperty, а методы доступа именуются GetHasFish и SetHasFish.

public class Aquarium : UIElement
{
    // Register an attached dependency property with the specified
    // property name, property type, owner type, and property metadata.
    public static readonly DependencyProperty HasFishProperty = 
        DependencyProperty.RegisterAttached(
      "HasFish",
      typeof(bool),
      typeof(Aquarium),
      new FrameworkPropertyMetadata(defaultValue: false,
          flags: FrameworkPropertyMetadataOptions.AffectsRender)
    );

    // Declare a get accessor method.
    public static bool GetHasFish(UIElement target) =>
        (bool)target.GetValue(HasFishProperty);

    // Declare a set accessor method.
    public static void SetHasFish(UIElement target, bool value) =>
        target.SetValue(HasFishProperty, value);
}
Public Class Aquarium
    Inherits UIElement

    ' Register an attached dependency property with the specified
    ' property name, property type, owner type, and property metadata.
    Public Shared ReadOnly HasFishProperty As DependencyProperty =
        DependencyProperty.RegisterAttached("HasFish", GetType(Boolean), GetType(Aquarium),
            New FrameworkPropertyMetadata(defaultValue:=False,
                flags:=FrameworkPropertyMetadataOptions.AffectsRender))

    ' Declare a get accessor method.
    Public Shared Function GetHasFish(target As UIElement) As Boolean
        Return target.GetValue(HasFishProperty)
    End Function

    ' Declare a set accessor method.
    Public Shared Sub SetHasFish(target As UIElement, value As Boolean)
        target.SetValue(HasFishProperty, value)
    End Sub

End Class

Акцессор get

Сигнатура метода доступа get — это public static object Get<property name>(DependencyObject target), где:

  • target — это свойство DependencyObject , из которого считывается присоединенное свойство. Тип target может быть более конкретным, чем DependencyObject. Например, метод доступа DockPanel.GetDock типизирует target как UIElement , потому что присоединенное свойство предназначено для установки на экземпляры UIElement. UiElement косвенно является производным от DependencyObject.
  • Тип возвращаемого значения может быть более конкретным, чем object. Например, метод GetDock определяет возвращаемое значение как Dock, потому что возвращаемое значение должно быть перечислением Dock.

Замечание

Аксессор get для присоединенного свойства необходим для поддержки привязки данных в средствах проектирования, таких как Visual Studio или Blend для Visual Studio.

Аксессор Set

Сигнатура метода доступа setpublic static void Set<property name>(DependencyObject target, object value), где:

  • target — это DependencyObject, на котором записано присоединенное свойство. Тип target может быть более конкретным, чем DependencyObject. Например, метод SetDock определяет target как UIElement, потому что присоединенное свойство предназначено для установки на экземпляры UIElement. UiElement косвенно является производным от DependencyObject.
  • Тип value может быть более конкретным, чем object. Например, методу SetDock требуется значение Dock. Загрузчик XAML должен иметь возможность создать value тип из строки разметки, представляющей значение присоединенного свойства. Таким образом, необходимо иметь поддержку преобразования типов, сериализатора значений или расширения разметки для используемого типа.

Атрибуты присоединенного свойства

WPF определяет несколько атрибутов .NET, которые предоставляют информацию о присоединенных свойствах для процессов рефлексии, а также для потребителей информации о рефлексии и свойствах, таких как дизайнеры. Конструкторы используют атрибуты WPF, определенные в .NET, чтобы ограничить свойства, отображаемые в окне свойств, и избежать перегрузки пользователей глобальным списком всех присоединенных свойств. Вы можете рассмотреть возможность применения этих атрибутов к своим собственным пользовательским присоединенным свойствам. Назначение и синтаксис атрибутов .NET описаны на следующих справочных страницах:

Подробнее

  • Дополнительные сведения о создании присоединенного свойства см. в разделе "Регистрация присоединенного свойства".
  • Дополнительные сценарии использования для свойств зависимостей и присоединенных свойств см. в разделе "Настраиваемые свойства зависимостей".
  • Можно зарегистрировать свойство как присоединенное, так и зависимое, и включить стандартные оболочки для свойств. Таким образом, свойство можно установить на элементе с помощью оболочек для свойств и на любом другом элементе, используя синтаксис присоединенного свойства XAML. Пример см. в разделе FrameworkElement.FlowDirection.

См. также