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


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

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

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

Предпосылки

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

Наследование по дереву элементов

Наследование значений свойств не совпадает с понятием наследования классов в объектно-ориентированном программировании, где производные классы наследуют члены базового класса. Этот вид наследования также активен в WPF, хотя в XAML унаследованные свойства базового класса предоставляются как атрибуты элементов XAML, представляющих производные классы.

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

В следующем примере показаны вложенные элементы в XAML. WPF регистрирует AllowDrop свойство зависимостей в UIElement классе с метаданными свойств, которые позволяют наследовать значение свойства и задает значение falseпо умолчанию. Свойство AllowDrop зависимости существует в элементах Canvas, StackPanel и Label, так как все они являются производными от UIElement. Так как для свойства canvas1 зависимости установлено значение true, потомки stackPanel1 и label1 наследуют true в качестве их значения AllowDrop.

<Canvas x:Name="canvas1" Grid.Column="0" Margin="20" Background="Orange" AllowDrop="True">
    <StackPanel Name="stackPanel1" Margin="20" Background="Green">
        <Label Name="label1" Margin="20" Height="40" Width="40" Background="Blue"/>
    </StackPanel>
</Canvas>

Вы также можете создать дерево элементов программным способом, добавив объекты элементов в коллекцию дочерних элементов другого объекта элемента. В процессе выполнения наследование значений свойств работает в дереве результирующих объектов. В следующем примере stackPanel2 добавляется в дочернюю коллекциюcanvas2. Аналогичным образом label2 добавляется в дочернюю коллекцию stackPanel2. Так как для свойства зависимости canvas2 задано значение true, элементы-потомки stackPanel2 и label2 наследуют true как свое значение AllowDrop.

Canvas canvas2 = new()
{
    AllowDrop = true
};
StackPanel stackPanel2 = new();
Label label2 = new();
canvas2.Children.Add(stackPanel2);
stackPanel2.Children.Add(label2);
Dim canvas2 As New Canvas With {
    .AllowDrop = True
}
Dim stackPanel2 As New StackPanel()
Dim label2 As New Label()
canvas2.Children.Add(stackPanel2)
stackPanel2.Children.Add(label2)

Практические приложения наследования значений свойств

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

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

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

Создание настраиваемого свойства, наследуемого

Можно сделать настраиваемое свойство зависимости наследуемым путем включения свойства Inherits в экземпляре FrameworkPropertyMetadata, а затем регистрации пользовательского свойства зависимости, используя тот же экземпляр метаданных. По умолчанию Inherits установлено на false в FrameworkPropertyMetadata. Создание наследуемого значения свойства влияет на производительность, поэтому установите Inherits как true только в том случае, если эта функция необходима.

При регистрации свойства зависимостей с Inherits включенным в метаданных используйте RegisterAttached метод, как описано в разделе "Регистрация присоединенного свойства". Кроме того, присвойте свойству значение по умолчанию, чтобы наследуемое значение существовало. Кроме того, может потребоваться создать обертку свойств с аксессорами get и set для типа владельца, так же, как и для неприсоединенного свойства зависимости. Таким образом можно задать значение свойства с помощью оболочки свойств владельца или производного типа. В следующем примере создается зависимое свойство, которое называется IsTransparent, с включенным Inherits и значением false по умолчанию. В этом примере также содержится оболочка свойств с аксессорами get и set.

public class Canvas_IsTransparentInheritEnabled : Canvas
{
    // Register an attached dependency property with the specified
    // property name, property type, owner type, and property metadata
    // (default value is 'false' and property value inheritance is enabled).
    public static readonly DependencyProperty IsTransparentProperty =
        DependencyProperty.RegisterAttached(
            name: "IsTransparent",
            propertyType: typeof(bool),
            ownerType: typeof(Canvas_IsTransparentInheritEnabled),
            defaultMetadata: new FrameworkPropertyMetadata(
                defaultValue: false,
                flags: FrameworkPropertyMetadataOptions.Inherits));

    // Declare a get accessor method.
    public static bool GetIsTransparent(Canvas element)
    {
        return (bool)element.GetValue(IsTransparentProperty);
    }

    // Declare a set accessor method.
    public static void SetIsTransparent(Canvas element, bool value)
    {
        element.SetValue(IsTransparentProperty, value);
    }

    // For convenience, declare a property wrapper with get/set accessors.
    public bool IsTransparent
    {
        get => (bool)GetValue(IsTransparentProperty);
        set => SetValue(IsTransparentProperty, value);
    }
}
Public Class Canvas_IsTransparentInheritEnabled
    Inherits Canvas

    ' Register an attached dependency property with the specified
    ' property name, property type, owner type, and property metadata
    ' (default value is 'false' and property value inheritance is enabled).
    Public Shared ReadOnly IsTransparentProperty As DependencyProperty =
        DependencyProperty.RegisterAttached(
            name:="IsTransparent",
            propertyType:=GetType(Boolean),
            ownerType:=GetType(Canvas_IsTransparentInheritEnabled),
            defaultMetadata:=New FrameworkPropertyMetadata(
                defaultValue:=False,
                flags:=FrameworkPropertyMetadataOptions.[Inherits]))

    ' Declare a get accessor method.
    Public Shared Function GetIsTransparent(element As Canvas) As Boolean
        Return element.GetValue(IsTransparentProperty)
    End Function

    ' Declare a set accessor method.
    Public Shared Sub SetIsTransparent(element As Canvas, value As Boolean)
        element.SetValue(IsTransparentProperty, value)
    End Sub

    ' For convenience, declare a property wrapper with get/set accessors.
    Public Property IsTransparent As Boolean
        Get
            Return GetValue(IsTransparentProperty)
        End Get
        Set(value As Boolean)
            SetValue(IsTransparentProperty, value)
        End Set
    End Property
End Class

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

Наследование значений свойств по границам дерева

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

Замечание

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

См. также