Общие сведения о вложенных свойствах зависимостей

Присоединенное свойство — это понятие, определяемое языком XAML. Присоединенное свойство предназначено для использования в качестве типа глобального свойства, которое может быть задано для любого объекта. В Windows Presentation Foundation (WPF) присоединенные свойства обычно определяются как особая форма свойства зависимости, не имеющего обычной "оболочки" свойства.

Требований

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

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

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

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

В XAML присоединенные свойства задаются с помощью синтаксиса ПоставщикПрисоединенногоСвойства.ИмяСвойства.

Ниже приведен пример того, как можно задать DockPanel.Dock в XAML:

<DockPanel>
  <CheckBox DockPanel.Dock="Top">Hello</CheckBox>
</DockPanel>

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

Кроме того, поскольку присоединенное свойство в XAML является атрибутом, который устанавливается в разметке, операция задания является значимой. Нельзя напрямую получить свойство в XAML, хотя существуют некоторые косвенные механизмы для сравнения значений, такие как триггеры в стилях (подробнее см. в разделе Стилизация и использование шаблонов).

Реализация присоединенного свойства в WPF

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

Как присоединенные свойства используются типом-владельцем

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

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

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

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

Пример присоединенного свойства, определенного родительским элементом

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

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

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

Присоединенные свойства в WPF не имеют типовых методов оболочки CLR для простого доступа get/set. Это связано с тем, что присоединенное свойство не обязательно является частью пространства имен CLR для экземпляров, в которых задано свойство. Тем не менее обработчик XAML должен иметь возможность задавать эти значения при анализе XAML. Для поддержки эффективного использования присоединенного свойства тип владельца присоединенного свойства должен реализовывать выделенные методы доступа в форме Get * PropertyName* и *Set PropertyName * * *. Такие специальные методы доступа также удобны для получения или задания присоединенного свойства в коде. С точки зрения кода присоединенное свойство аналогично резервному полю с методами доступа к методам вместо методов доступа к свойствам. Такое резервное поле может существовать для любого объекта и не требует специального определения.

В следующем примере кода показано задание присоединенного свойства в коде. В этом примере myCheckBox — это экземпляр CheckBox класса.

DockPanel myDockPanel = new DockPanel();
CheckBox myCheckBox = new CheckBox();
myCheckBox.Content = "Hello";
myDockPanel.Children.Add(myCheckBox);
DockPanel.SetDock(myCheckBox, Dock.Top);
Dim myDockPanel As New DockPanel()
Dim myCheckBox As New CheckBox()
myCheckBox.Content = "Hello"
myDockPanel.Children.Add(myCheckBox)
DockPanel.SetDock(myCheckBox, Dock.Top)

Как и в случае с XAML, если myCheckBox не было добавлено в качестве дочернего элемента в myDockPanel четвертой строке кода, пятая строка кода не будет вызывать исключение, но значение свойства не будет взаимодействовать с DockPanel родительским объектом и, таким образом, ничего не сделает. Только DockPanel.Dock значение, установленное в дочернем элементе вместе с присутствием DockPanel родительского элемента, приведет к эффективному поведению в приложении, готовом для просмотра. (В этом случае вы может задать присоединенное свойство, а затем подключиться к дереву. Аналогично, можно подключиться к дереву, а затем задать присоединенное свойство. Любая последовательность действий дает тот же результат.)

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

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

Если вы хотите разрешить наследование значений свойства, следует использовать присоединенные свойства, вместо неприсоединенных свойств зависимостей. Дополнительные сведения см. в разделе наследование значений свойств.

Пользовательские присоединенные свойства

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

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

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

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

Как упоминалось ранее, свойство следует регистрировать как присоединенное, если требуется использовать наследование значения свойства.

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

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

Определите присоединенное свойство как свойство зависимостей, объявляя public static readonly поле типа DependencyProperty . Это поле определяется с помощью возвращаемого значения RegisterAttached метода. Имя поля должно совпадать с именем присоединенного свойства, добавленного со строкой Property , чтобы соответствовать установленному шаблону WPF именования идентифицирующих полей относительно свойств, которые они представляют. Поставщик присоединенного свойства также должен предоставлять статические методы Get * PropertyName* и Set * PropertyName* в качестве методов доступа к присоединенному свойству. не удается выполнить это действие, так как система свойств не может использовать присоединенное свойство.

Примечание

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

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

Сигнатура для метода доступа Get * PropertyName* должна иметь следующее значение:

public static object GetPropertyName(object target)

  • Объект target можно указать как более конкретный тип в реализации. Например, метод присваивает DockPanel.GetDock параметру значение UIElement , поскольку присоединенное свойство предназначено только для UIElement экземпляров.

  • Возвращаемое значение можно указать как более конкретный тип в реализации. Например, GetDock метод вводит тип Dock , так как значение может быть задано только для этого перечисления.

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

Сигнатура для метода доступа Set * PropertyName* должна иметь следующие значения:

public static void SetPropertyName(object target, object value)

  • Объект target можно указать как более конкретный тип в реализации. Например, SetDock метод вводит значение UIElement , поскольку присоединенное свойство предназначено только для UIElement экземпляров.

  • Объект value можно указать как более конкретный тип в реализации. Например, SetDock метод вводит тип Dock , так как значение может быть задано только для этого перечисления. Помните, что значением этого метода являются входные данные, поступающие от загрузчика XAML, когда он встречает присоединенное свойство в использовании присоединенного свойства в макете. Эти входные данные являются значением, указанным как значение атрибута XAML в разметке. Таким образом, необходимо обеспечить поддержку преобразования типов, сериализатора значений или расширений разметки для используемого типа так, чтобы соответствующий тип можно было создать из значения атрибута (которое, в конечном счете, является просто строкой).

В следующем примере показана регистрация свойства зависимостей (с помощью RegisterAttached метода), а также методы доступа Get * PropertyName* и Set * PropertyName*. В этом примере именем присоединенного свойства является IsBubbleSource. Таким образом, методы доступа должны называться GetIsBubbleSource и SetIsBubbleSource.

public static readonly DependencyProperty IsBubbleSourceProperty = DependencyProperty.RegisterAttached(
  "IsBubbleSource",
  typeof(Boolean),
  typeof(AquariumObject),
  new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsRender)
);
public static void SetIsBubbleSource(UIElement element, Boolean value)
{
  element.SetValue(IsBubbleSourceProperty, value);
}
public static Boolean GetIsBubbleSource(UIElement element)
{
  return (Boolean)element.GetValue(IsBubbleSourceProperty);
}
Public Shared ReadOnly IsBubbleSourceProperty As DependencyProperty = DependencyProperty.RegisterAttached("IsBubbleSource", GetType(Boolean), GetType(AquariumObject), New FrameworkPropertyMetadata(False, FrameworkPropertyMetadataOptions.AffectsRender))
Public Shared Sub SetIsBubbleSource(ByVal element As UIElement, ByVal value As Boolean)
    element.SetValue(IsBubbleSourceProperty, value)
End Sub
Public Shared Function GetIsBubbleSource(ByVal element As UIElement) As Boolean
    Return CType(element.GetValue(IsBubbleSourceProperty), Boolean)
End Function

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

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

Обучение Дополнительные сведения о вложенных свойствах

  • Дополнительные сведения о создании присоединенного свойства см. в разделе Регистрация присоединенного свойства.

  • Более сложные сценарии использования свойств зависимостей и присоединенных свойств см. в разделе Пользовательские свойства зависимостей.

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

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