- •«Комп’ютерні технології та програмування»
- •Оглавление
- •Лабораторная работа 1 Знакомство с wpf
- •Теоретические сведения
- •1. Знакомство с редактором xaml
- •2.Создание приложения wpf
- •Контрольные вопросы
- •Лабораторная работа 2 Подробное введение в разработку приложений wpf
- •Теоретические сведения
- •1. Ознакомление с управлением проектами wpf в msVisualStudio
- •3) Создание обработчиков событий
- •Задание к лабораторной работе
- •Варианты индивидуальных заданий
- •2. Создание тестового приложения wpf
- •Задание к лабораторной работе
- •Варианты индивидуальных заданий
- •Контрольные вопросы
- •Лабораторная работа 3 Макет программы и основные элементы управления
- •Теоретически сведения
- •1. Макет в wpf
- •2. Новые возможности wpf
- •3. Элемент управления Canvas
- •4. Элементуправления StackPanel
- •5. Элементуправления WrapPanel
- •6. Элемент управления DockPanel
- •7. Элемент Grid
- •Задание к лабораторной работе
- •Варианты индивидуальных заданий
- •Контрольные вопросы
- •Лабораторная работа 4
- •Xaml и код, расширения разметки и ресурсы
- •Теоретически сведения
- •2. Ссылки на ресурсы в wpf
- •Задание к лабораторной работе
- •Варианты индивидуальных заданий
- •Контрольные вопросы
- •Лабораторная работа 6 Свойства зависимости
- •Теоретически сведения
- •1. Особенности свойств clr
- •2. Наследование значений свойств зависимости
- •3. Присоединенные свойства
- •4. Метаданныесвойствзависимости
- •5. Проверка допустимости значения
- •Задание к лабораторной работе
- •Варианты индивидуальных заданий
- •Контрольные вопросы
- •Лабораторная работа 7 Привязка данных
- •Теоретически сведения
- •1. Концепция привязки данных
- •2. Свойство DataContext
- •3. Основные понятия привязки данных
- •4. Синтаксис привязки данных
- •5. Привязка к элементам интерфейса пользователя
- •6. Привязка к xml
- •7. Привязка к коллекции
- •8. Преобразователи значений привязки данных
- •9. Проверкапривязкиданных
- •Задание к лабораторной работе
- •Варианты индивидуальных заданий
- •Контрольные вопросы
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"/>
