Общие сведения о вложенных свойствах (WPF .NET)

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

Важно!

Документация руководства по классическим приложениям для .NET 6 и .NET 5 (включая .NET Core 3.1) находится в разработке.

Предварительные требования

В статье предполагается наличие базовых знаний о свойствах зависимостей и прочитаны Общие сведения о свойствах зависимостей. для выполнения примеров, описанных в этой статье, полезно ознакомиться с 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 применимо только действие SET. Нельзя напрямую получить значение свойства через XAML, хотя существуют некоторые косвенные механизмы для сравнения значений, такие как триггеры в стилях.

Вложенные свойства в WPF

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

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

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

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

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

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

DockPanelDockPanel.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.DockPanel.ZIndex , и Canvas.Top все примеры существующих свойств макета. В сценарии макета дочерние элементы элемента, контролирующего макет, могут выражать требования к макету к родительскому макету и задавать значение для присоединенного свойства, определенного родительским элементом.

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

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

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

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

Если класс определяет присоединенное свойство только для использования другими типами, то классу не требуется производный от 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 метод доступа вводит targetUIElement , так как присоединенное свойство должно быть задано UIElement для экземпляров. UiElement косвенно наследуется от DependencyObject .
  • Тип возвращаемого значения может быть более конкретным, чем object . Например, GetDock метод вводит возвращаемое значение так, как Dock возвращаемое значение должно быть Dock перечислением.

Примечание

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

Метод доступа set

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

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

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

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

Подробнее

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

См. также раздел