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


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

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

Необходимые условия

В этом разделе предполагается, что у вас есть некоторые базовые знания о системе типов .NET и объектно-ориентированном программировании. Чтобы следовать примерам в этом разделе, вы также должны понять XAML и узнать, как писать приложения WPF. Дополнительную информацию см. в разделе Пошаговое руководство: Мое первое классическое приложение WPF.

Свойства зависимостей и свойства CLR

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

Назначение свойств зависимостей — предоставить способ вычисления значения свойства на основе значения других входных данных. Эти другие входные данные могут включать системные свойства, такие как темы и предпочтения пользователя, механизмы определения свойств в реальном времени, такие как привязка данных и анимации/раскадровки, шаблоны многократного использования, такие как ресурсы и стили, или значения, известные через родительско-дочерние отношения с другими элементами в иерархии элементов. Кроме того, свойство зависимостей можно реализовать для обеспечения автономной проверки, значений по умолчанию, обратных вызовов, отслеживающих изменения других свойств, и системы, которая может принуждать значения свойств на основе потенциальной информации среды выполнения. Производные классы также могут изменять некоторые характеристики существующего свойства, переопределяя метаданные свойства зависимостей, а не переопределяя фактическую реализацию существующих свойств или создавая новые свойства.

В справочнике по пакету SDK можно определить, какое свойство является свойством зависимостей по присутствию раздела "Сведения о свойстве зависимостей" на управляемой эталонной странице для этого свойства. В разделе сведений о свойстве зависимости предоставлена ссылка на поле идентификатора DependencyProperty для данного свойства, а также список параметров метаданных, установленных для него, информация о переопределении для каждого класса и другие детали.

Свойства зависимостей поддерживают свойства CLR

Свойства зависимостей и система свойств WPF расширяют функциональные возможности свойств, предоставляя тип, который поддерживает свойство, в качестве альтернативы реализации стандартному шаблону резервного копирования свойства с частным полем. Имя этого типа — DependencyProperty. Другой важный тип, определяющий систему свойств WPF, является DependencyObject. DependencyObject определяет базовый класс, который может регистрировать и владеть свойством зависимостей.

Ниже перечислены терминология, используемая со свойствами зависимостей:

  • свойство зависимостей: свойство, поддерживаемое DependencyProperty.

  • Идентификатор свойства зависимости: экземпляр DependencyProperty, который получается в качестве возвращаемого значения при регистрации свойства зависимости, а затем хранится в качестве статического члена класса. Этот идентификатор используется в качестве параметра для многих API, взаимодействующих с системой свойств WPF.

  • CLR "оболочка": фактические реализации получения и задания для свойства. Эти реализации включают идентификатор свойства зависимостей, используя его в вызовах GetValue и SetValue, что обеспечивает поддержку свойства с помощью системы свойств WPF.

В следующем примере определяется свойство зависимостей IsSpinning и отображается связь идентификатора DependencyProperty с свойством, которое он поддерживает.

public static readonly DependencyProperty IsSpinningProperty =
    DependencyProperty.Register(
    "IsSpinning", typeof(Boolean),
    typeof(MyCode)
    );
public bool IsSpinning
{
    get { return (bool)GetValue(IsSpinningProperty); }
    set { SetValue(IsSpinningProperty, value); }
}
Public Shared ReadOnly IsSpinningProperty As DependencyProperty =
    DependencyProperty.Register("IsSpinning",
                                GetType(Boolean),
                                GetType(MyCode))

Public Property IsSpinning() As Boolean
    Get
        Return CBool(GetValue(IsSpinningProperty))
    End Get
    Set(ByVal value As Boolean)
        SetValue(IsSpinningProperty, value)
    End Set
End Property

Важно следовать правилам именования для свойства и его сопутствующего DependencyProperty поля. Имя поля всегда соответствует имени свойства, к которому добавляется суффикс Property. Дополнительные сведения об этом соглашении и причинах этого см. в разделе Настраиваемые свойства зависимостей.

Задание значений свойств

Свойства можно задать в коде или в XAML.

Задание значений свойств в XAML

В следующем примере XAML указывается цвет фона кнопки красным цветом. В этом примере показан случай, когда простое строковое значение атрибута XAML преобразуется синтаксическим анализатором XAML WPF в тип WPF (Colorчерез SolidColorBrush) в сгенерированном коде.

<Button Background="Red" Content="Button!"/>

XAML поддерживает различные формы синтаксиса для задания свойств. Какой синтаксис, используемый для конкретного свойства, будет зависеть от типа значения, используемого свойством, а также других факторов, таких как наличие преобразователя типов. Дополнительные сведения о синтаксисе XAML для установки свойств см. в XAML в WPF и синтаксисе XAML в деталях.

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

<Button Content="Button!">
  <Button.Background>
    <ImageBrush ImageSource="wavy.jpg"/>
  </Button.Background>
</Button>

Задание свойств в коде

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

Button myButton = new Button();
myButton.Width = 200.0;
Dim myButton As New Button()
myButton.Width = 200.0

Получение значения свойства также является вызовом реализации get "оболочка":

double whatWidth;
whatWidth = myButton.Width;
Dim whatWidth As Double
whatWidth = myButton.Width

Вы также можете вызывать API системы свойств GetValue и SetValue напрямую. Обычно это не обязательно, если вы используете существующие свойства (оболочки удобнее и обеспечивают лучшую экспозицию свойства для средств разработчика), но вызов API напрямую подходит для определенных сценариев.

Свойства можно также задать в XAML, а затем получить к ним доступ позже в коде через backend. Дополнительные сведения см. в Code-Behind и в XAML в WPF.

Функциональные возможности свойств, предоставляемые свойством зависимостей

Свойство зависимостей предоставляет функциональные возможности, расширяющие функциональные возможности свойства в отличие от свойства, поддерживаемого полем. Часто такие функциональные возможности представляют или поддерживают одну из следующих конкретных функций:

Ресурсы

Значение свойства зависимостей можно задать, ссылаясь на ресурс. Ресурсы обычно указываются в качестве значения свойства Resources корневого элемента страницы или приложения (эти расположения обеспечивают наиболее удобный доступ к ресурсу). В следующем примере показано, как определить ресурс SolidColorBrush.

<DockPanel.Resources>
  <SolidColorBrush x:Key="MyBrush" Color="Gold"/>
</DockPanel.Resources>

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

<Button Background="{DynamicResource MyBrush}" Content="I am gold" />

На этот конкретный ресурс ссылается расширение разметки DynamicResource (в XAML WPF можно использовать статическую или динамическую ссылку на ресурсы). Чтобы воспользоваться динамической ссылкой на ресурс, необходимо устанавливать свойство зависимости, поэтому это именно использование динамической ссылки на ресурс, которое обеспечивается системой свойств WPF. Дополнительные сведения см. в ресурсах XAML и.

Заметка

Ресурсы рассматриваются как локальное значение, что означает, что при установке другого локального значения вы исключите ссылку на ресурсы. Дополнительные сведения см. в разделе Приоритет значения свойства зависимостей.

Привязка данных

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

В следующем примере задается свойство Content для Buttonс помощью привязки, объявленной в XAML. Привязка использует наследуемый контекст данных и источник данных XmlDataProvider (не показан). Сама привязка указывает требуемое исходное свойство с помощью XPath в источнике данных.

<Button Content="{Binding XPath=Team/@TeamName}"/>

Заметка

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

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

Стили

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

В следующем примере сначала создается простой стиль, который определён в словаре Resources (не показан), а затем этот стиль непосредственно применяется к свойству Style для Button. Установщик стиля задает свойству Background стилизованного Button значение зеленого цвета.

<Style x:Key="GreenButtonStyle">
  <Setter Property="Control.Background" Value="Green"/>
</Style>
<Button Style="{StaticResource GreenButtonStyle}">I am green!</Button>

Для получения дополнительной информации о стилях и шаблонах см. .

Анимации

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

В следующем примере анимируется Background в свойстве Button. Технически, Background анимируется, используя синтаксис элемента свойства, чтобы сначала указать пустой SolidColorBrush в качестве Background, а затем свойство Color этого SolidColorBrush становится непосредственно анимируемым свойством.

<Button>I am animated
  <Button.Background>
    <SolidColorBrush x:Name="AnimBrush"/>
  </Button.Background>
  <Button.Triggers>
    <EventTrigger RoutedEvent="Button.Loaded">
      <BeginStoryboard>
        <Storyboard>
          <ColorAnimation
            Storyboard.TargetName="AnimBrush" 
            Storyboard.TargetProperty="(SolidColorBrush.Color)"
            From="Red" To="Green" Duration="0:0:5" 
            AutoReverse="True" RepeatBehavior="Forever" />
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>
  </Button.Triggers>
</Button>

Дополнительные сведения об анимации свойств см. в Обзор анимации и Обзор раскадровки.

Переопределения метаданных

Вы можете изменить определенные аспекты поведения свойства зависимости, переопределив метаданные для этого свойства при наследовании от класса, который первоначально зарегистрировал это свойство зависимости. Переопределение метаданных зависит от идентификатора DependencyProperty. Переопределение метаданных не требует повторного выполнения свойства. Изменение метаданных обрабатывается системой свойств встроенными средствами; каждый класс потенциально содержит отдельные метаданные для всех свойств, унаследованных от базовых классов, для каждого типа.

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

public class SpinnerControl : ItemsControl
{
    static SpinnerControl()
    {
        DefaultStyleKeyProperty.OverrideMetadata(
            typeof(SpinnerControl),
            new FrameworkPropertyMetadata(typeof(SpinnerControl))
        );
    }
}
Public Class SpinnerControl
    Inherits ItemsControl
    Shared Sub New()
        DefaultStyleKeyProperty.OverrideMetadata(GetType(SpinnerControl), New FrameworkPropertyMetadata(GetType(SpinnerControl)))
    End Sub
End Class

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

Наследование значений свойства

Элемент может наследовать значение свойства зависимостей от родительского элемента в дереве объектов.

Заметка

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

В следующем примере показана привязка и задает свойство DataContext, указывающее источник привязки, который не отображался в предыдущем примере привязки. Любые последующие привязки в дочерних объектах не должны указывать источник, так как они могут использовать унаследованное значение от объекта DataContext в родительском объекте StackPanel. (Кроме того, дочерний объект может вместо этого напрямую указать собственные DataContext или Source в Bindingи намеренно не использовать унаследованное значение для контекста данных своих привязок.)

<StackPanel Canvas.Top="50" DataContext="{Binding Source={StaticResource XmlTeamsSource}}">
  <Button Content="{Binding XPath=Team/@TeamName}"/>
</StackPanel>

Для получения дополнительной информации см. раздел Наследование значений свойств.

Интеграция конструктора WPF

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

Приоритет значения свойства зависимостей

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

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

Заметка

В документации по пакету SDK иногда используются термины "локальное значение" или "локально заданное значение" при обсуждении свойств зависимостей. Локально заданное значение — это значение свойства, которое устанавливается непосредственно в экземпляре объекта в коде или в качестве атрибута элемента в XAML.

В принципе, для первой кнопки свойство устанавливается дважды, но применяется только одно значение: значение с наивысшим приоритетом. Локально заданное значение имеет наивысший приоритет (за исключением запущенной анимации, но анимация не применяется в этом примере), поэтому локально заданное значение используется вместо значения набора стилей для фона на первой кнопке. Вторая кнопка не имеет локального значения (и нет другого значения с более высоким приоритетом, чем метод задания стиля) и таким образом фон в этой кнопке поступает из метода задания стиля.

<StackPanel>
  <StackPanel.Resources>
    <Style x:Key="{x:Type Button}" TargetType="{x:Type Button}">
     <Setter Property="Background" Value="Red"/>
    </Style>
  </StackPanel.Resources>
  <Button Background="Green">I am NOT red!</Button>
  <Button>I am styled red</Button>
</StackPanel>

Почему приоритет свойств зависимостей существует?

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

Заметка

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

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

  • Присоединенное свойство — это тип свойства, поддерживающего специализированный синтаксис в XAML. Присоединенное свойство часто не имеет 1:1 соответствия со свойством среды CLR и не обязательно является свойством зависимости. Типичным назначением присоединенного свойства является разрешение дочерних элементов сообщать значения свойств родительскому элементу, даже если родительский элемент и дочерний элемент не обладают этим свойством в составе перечислений членов класса. Предоставление возможности дочерним элементам информировать родительский элемент о том, как они должны быть представлены в пользовательском интерфейсе, является одним из основных сценариев. Пример см. в разделе Dock или Left. Дополнительные сведения см. в разделе "Общие сведения о присоединенных свойствах".

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

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

См. также