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

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

Важно!

Документация по рабочему столу для .NET 7 и .NET 6 находится в стадии разработки.

Необходимые компоненты

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

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

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

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

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

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

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

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

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

Примечание.

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

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

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

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

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

Примечание.

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

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

Стили

Стили и шаблоны являются убедительными причинами использования свойств зависимостей. Стили особенно полезны для задания свойств, определяющих пользовательский интерфейс приложения. Обычно стили определяются в 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. Присоединенное свойство часто не имеет соответствия 1:1 с свойством cl language runtime и не обязательно является свойством зависимостей. Основной целью присоединенного свойства является разрешение дочерних элементов сообщать значения свойств родительскому элементу, даже если родительский элемент и дочерний элемент не включают это свойство как часть списков членов класса. Одним из основных сценариев является включение дочернего элемента для информирования родительских элементов о том, как их представить в пользовательском интерфейсе. Примеры см Dock . и Left. Дополнительные сведения см. в разделе "Общие сведения о присоединенных свойствах".

См. также