Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Wpf-АК11.doc
Скачиваний:
6
Добавлен:
01.03.2025
Размер:
3 Мб
Скачать
☆

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

Еще один вариант — наследовать значения из свойства зависимости, объявленного для совершенно другого элемента (рис. 6.1):

Рис. 6.1 - Пример наследования значений

На рисунке ниже показан код XAML.

Рис. 6.2 - Код XAML

Как видно, если свойство TextElement.FontSize объявлено на уровне объекта Window, любой элемент управления, для которого не объявлено собственное значение TextElement.FontSize, будет наследовать значение свойства TextElement.FontSize, объявленного для объекта Window. Но как такое может быть? Элемент TextElement — не Window или Label. Как же все это работает? Подсистема свойств WPF очень хитрая, фактически она позволяет объявлять свойства зависимости так, что они могут использоваться другими классами, отличными от тех, в которых объявляется свойство зависимости. Они называются присоединенными свойствами.

Класс Windowв этом примере использует присоединенное свойство. Прекрасно. Возможность наследования, которую обеспечивает подсистема свойств WPF при объявлении свойства зависимости. Чтобы разобраться в этом, рассмотрим несколько снимков экрана превосходного декомпилятора .NET. Мы также посмотрим на классы, используемые в этом примере, чтобы сохранить контекст.

Свойство TextElement.FontSize фактически относится к классу System.Windows.Documents.TextElement в библиотеке PresentationFramework.dll. Именно здесь первый раз объявляется свойство зависимости FontSize. Свойство объявляется как присоединенное. Это значит, что другие классы могут ссылаться на это свойство зависимости с использованием синтаксиса TextElement.FontSize, даже если они не имеют ничего общего с классом TextElement (рис. 6.3).

Рис. 6.3 - Disassemble

Рис. 6.4 - Disassembler

Свойство TextElement.FontSize объявляется с метаданными Inherits (рис. 6.5). Это позволяет элементам управления с этим присоединенным свойством наследовать значение от вышестоящего события в визуальном дереве, если они не объявляют новое значение этого свойства.

Рис. 6.5 - Страница MSDN

На самом деле элемент TextElement не объявляет свойство зависимости FontSize, а само свойство — присоединенное и помечено метаданными Inherits. Например, об элементе System.Windows.Controls.Label, как в нашем примере.

Элемент System.Windows.Controls.Label в действительности не объявляет свойство зависимости FontSize. Нам придется двигаться по объектному дереву наследования, пока мы не дойдем до элемента System.Windows.Controls.Control, в котором находится объявление свойства FontSize. Мы увидим следующее (рис. 6.6).

Рис 6.6 - Свойства элемента

Третий элемент System.Windows.Controls.Label на снимке экрана демонстрационного проекта обладает другим значением FontSize, потому что не наследует значение свойства (из свойства TextElement.FontSize, заданного в элементе Window1), а явно объявляет собственное, тем самым переопределяя наследуемое значение, получаемое от объекта Window1.

Для демонстрации работы свойства TextElement.FontSize приведен проект в рамках общего решения. Проект называется DP_Custom_Inherited_Properties и при выполнении выглядит следующим образом (рис. 6.7).

Рис.6.7 - Наследования свойств

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

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Navigation;

using System.Windows.Shapes;

namespace Custom_Inherited_DPs

{

   ///

   /// Этопростойподкласскласса Button, наследующийсвойствозависимости MinDate

   ///

   public class MyCustomButton : Button

   {

       ///

       /// Создаетновыйобъект MyCustomButton идобавляеткласс MyCustomButton

       /// в дочерние объекты свойства зависимости MyStackPanel.MinDate

       ///

       static MyCustomButton()

       {

           MinDateProperty = MyStackPanel.MinDateProperty.AddOwner(typeof(MyCustomButton),

           new FrameworkPropertyMetadata(DateTime.MinValue,

           FrameworkPropertyMetadataOptions.Inherits));

       }

       #region Inherited DP declaration

       ///

       /// Объявлениесвойствазависимости MinDate

       ///

       public static readonly DependencyProperty MinDateProperty;

       public DateTime MinDate

       {

           get { return (DateTime)GetValue(MinDateProperty); }

           set { SetValue(MinDateProperty, value); }

       }

       #endregion

   }

   ///

   /// Это простой подкласс класса StackPanel, являющийся источником для

   /// наследуемого свойства зависимости MinDate

   ///

   public class MyStackPanel : StackPanel

   {

       ///

       /// Создает новый объект MyStackPanelи регистрирует свойство зависимости MinDate

       ///

       static MyStackPanel()

       {

           MinDateProperty = DependencyProperty.Register("MinDate",

           typeof(DateTime),

           typeof(MyStackPanel),

           new FrameworkPropertyMetadata(DateTime.MinValue,

           FrameworkPropertyMetadataOptions.Inherits));

       }

       #region Source for Inherited MinDate DP declaration

       ///

       /// Объявлениесвойствазависимости MinDate

       ///

       public static readonly DependencyProperty MinDateProperty;

       public DateTime MinDate

       {

           get { return (DateTime)GetValue(MinDateProperty); }

           set { SetValue(MinDateProperty, value); }

       }

       #endregion

   }

}

Как видно из примера, было определено два класса: MyStackPanel (подкласс StackPanel) служит источником для наследуемого свойства зависимости MinDate. Другой класс, MyButton (подкласс Button), объявляет наследуемое свойство. При этом важно узнать, как объявляется свойство зависимости в классе MyButton. Посмотрим на следующий фрагмент кода.

MinDateProperty = MyStackPanel.MinDateProperty.AddOwner(typeof(MyCustomButton),

new FrameworkPropertyMetadata(DateTime.MinValue, FrameworkPropertyMetadataOptions.Inherits));

Как видно из кода, собственное свойство зависимости MinDate элемента MyStackPanel используется для добавления владельца типа MyButton.

Это код программной части. Ниже приведена разметка XAML.

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   xmlns:local="clr-namespace:Custom_Inherited_DPs"

   xmlns:sys="clr-namespace:System;assembly=mscorlib"

   WindowStartupLocation="CenterScreen"

   Title="Using custom inherited DPs" Height="400" Width="400">

                   Content="{Binding RelativeSource={x:Static RelativeSource.Self},

                   Path=MinDate}"

               Height="20"/>

Свойство зависимости MinDate задается только в экземпляре MyStackPanel в следующей строке.

Поскольку свойство зависимости MinDate элемента MyCustomButton наследует это значение (благодаря тому, как объявлено свойство зависимости MinDate элемента MyCustomButton), его совсем не требуется объявлять. Оно просто наследуется от свойства зависимости MinDate элемента MyStackPanel. И оно отображается с использованием привязки данных RelativeSource.

   Content="{Binding RelativeSource={x:Static RelativeSource.Self},

   Path=MinDate}"

   Height="20"/>

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]