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


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

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

Предпосылки

В этой статье предполагается базовое знание системы типов .NET и объектно-ориентированного программирования. Чтобы следовать примерам в этой статье, будет полезно понять XAML и уметь писать приложения WPF. Дополнительные сведения см. в руководстве по созданию нового приложения WPF с помощью .NET.

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

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

Назначение свойств зависимостей — предоставить способ вычисления значения свойства на основе значения других входных данных, таких как:

  • Системные свойства, такие как темы и предпочтения пользователя.
  • Механизмы определения свойств точно вовремя, такие как привязка данных и анимация/сюжетные линии.
  • Шаблоны с несколькими использованием, такие как ресурсы и стили.
  • Значения, определяемые через отношения "родитель-дитя" с другими элементами в дереве элементов.

Кроме того, свойство зависимости может предоставить:

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

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

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

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

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

Ниже приведены некоторые часто используемые термины:

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

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

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

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

public static readonly DependencyProperty IsSpinningProperty = DependencyProperty.Register(
    "IsSpinning", typeof(bool),
    typeof(MainWindow)
    );

public bool IsSpinning
{
    get => (bool)GetValue(IsSpinningProperty);
    set => SetValue(IsSpinningProperty, value);
}
Public Shared ReadOnly IsSpinningProperty As DependencyProperty =
    DependencyProperty.Register("IsSpinning", GetType(Boolean), GetType(MainWindow))

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

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

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

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

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

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

<Button Content="I am red" Background="Red"/>

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

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

<Button Content="I have an image background">
    <Button.Background>
        <ImageBrush ImageSource="stripes.jpg"/>
    </Button.Background>
</Button>

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

Установка значений свойств зависимостей в коде чаще всего заключается в вызове реализации set, предоставляемой CLR "оболочкой":

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

Получение значения свойства по сути представляет собой вызов реализации "оболочки" get.

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

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

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

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

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

Ресурсы

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

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

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

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

В XAML WPF можно использовать статическую или динамическую ссылку на ресурсы. Этот конкретный ресурс ссылается как DynamicResource

Замечание

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

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

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

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

<Button Content="{Binding Source={StaticResource TestData}, XPath=test[1]/@text}"/>

Замечание

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

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

Стили

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

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

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

Дополнительные сведения см. в разделе "Стилизация" и "Шаблон".

Анимации

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

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

<Button Content="I am animated">
    <Button.Background>
        <SolidColorBrush x:Name="AnimBrush"/>
    </Button.Background>
    <Button.Triggers>
        <EventTrigger RoutedEvent="FrameworkElement.Loaded">
            <BeginStoryboard>
                <Storyboard>
                    <ColorAnimation
                        Storyboard.TargetName="AnimBrush" 
                        Storyboard.TargetProperty="(SolidColorBrush.Color)"
                        From="Blue" To="White" Duration="0:0:1" 
                        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 TestData}}">
    <Button Content="{Binding XPath=test[2]/@text}"/>
</StackPanel>

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

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

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

Очередность значений свойств зависимостей

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

Замечание

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

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

<StackPanel>
    <StackPanel.Resources>
        <Style x:Key="{x:Type Button}" TargetType="{x:Type Button}">
            <Setter Property="Background" Value="Orange"/>
        </Style>
    </StackPanel.Resources>
    <Button>I am styled orange</Button>
    <Button Background="Pink">I am locally set to pink (not styled orange)</Button>
</StackPanel>

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

Локальные значения имеют приоритет над значениями стилей оформления, что обеспечивает возможность локального контроля свойств элементов. Дополнительные сведения см. в разделе приоритет значения свойства зависимостей.

Замечание

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

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

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

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

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

См. также