Свойства XAML

98

Простые свойства и конвертеры типов

Как вы уже видели, атрибуты элемента устанавливают свойства соответствующего объекта. Например, текстовые поля конфигурируют выравнивание, поля и шрифт:

<TextBox Name="txt1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
              FontFamily="Arial" FontSize="20" Foreground="Blue"></TextBox>

Чтобы это заработало, класс System.Windows.Controls.TextBox должен предоставить следующие свойства: VerticalAlignment, HorizontalAlignment, FontFamily, FontSize и Foreground.

Чтобы заставить эту систему работать, анализатор XAML должен выполнить больше работы, чем может показаться на первый взгляд. Значение в атрибуте XAML всегда представлено простой строкой. Однако свойства объекта могут быть любого типа .NET. В предыдущем примере было два свойства, использующих перечисления (VerticalAlignment и HorizontalAlignment), одна строка (FontFamily), одно целое число (FontSize) и один объект Brush (Foreground).

Чтобы преодолеть зазор между строковыми значениями и не строковыми свойствами, анализатор XAML должен выполнить преобразование. Это преобразование осуществляется конвертерами типов — базовой частью инфраструктуры .NET, которая существует еще со времен .NET 1.0.

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

Если в объявлении свойства или объявлении класса не оказывается ассоциированного конвертера типа, то анализатор XAML генерирует ошибку.

Эта система проста и гибка. Если вы устанавливаете конвертер типа на уровне класса, то этот конвертер применяется к каждому свойству, использующему этот класс. С другой стороны, если вы хотите обеспечить тонкую настройку работы конвертера типа для конкретного свойства, то вместо этого можете применять атрибут TypeConverter объявления свойства.

Формально возможно использовать конвертеры типов в коде, но синтаксис при этом несколько мудреный. Почти всегда лучше непосредственно установить свойство — это не только быстрее, но также позволяет избежать потенциальных ошибок от опечаток в строках, которые не проявляются до момента выполнения. (Эта проблема не затрагивает XAML, поскольку разметка XAML анализируется и проверяется во время компиляции.) Конечно, прежде чем можно будет устанавливать свойства в элементе WPF, необходимо узнать немного больше о базовых свойствах WPF и типах данных.

Сложные свойства

Как бы ни были удобны конвертеры типов, они подходят не для всех сценариев. Например, некоторые свойства являются полноценными объектами с собственными наборами свойств. Хотя можно создать строковое представление, которое будет использовать конвертер типа, этот синтаксис может оказаться трудным в применении, к тому же он подвержен ошибкам.

К счастью, XAML предусматривает другой выбор: синтаксис "свойство-элемент". С помощью этого синтаксиса можно добавлять дочерний элемент с именем в форме РодительскийЭлемент.ИмяСвойства. Например, у TextBox имеется свойство Background, которое позволяет указывать кисть, используемую для рисования области, находящейся под элементами управления. Чтобы применить сложную кисть — более совершенную, чем сплошное заполнение цветом, — понадобится добавить дочерний дескриптор по имени TextBox.Background.

Ключевая деталь, которая заставляет это работать — точка (.) в имени элемента. Это отличает свойства от других типов и вложенного содержимого.

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

<TextBox Name="txt1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
                 FontFamily="Arial" FontSize="20" Foreground="Blue">
            <TextBox.Background>
                <!-- Задаем градиентную заливку -->
                <LinearGradientBrush>
                    <LinearGradientBrush.GradientStops>
                        <GradientStop Offset="0.00" Color="White" />
                        <GradientStop Offset="0.30" Color="Red" />
                        <GradientStop Offset="1.00" Color="Violet" />
                    </LinearGradientBrush.GradientStops>
                </LinearGradientBrush>
            </TextBox.Background>
        </TextBox>

LinearGradientBrush является частью набора пространств имен WPF, так что для дескрипторов можно применять пространство имен XML по умолчанию. Однако просто создать LinearGradientBrush недостаточно; нужно также указать цвета градиента. Это делается заполнением свойства LinearGradientBrush.GradientStops коллекцией объектов GradientStop.

Опять-таки, свойство GradientStops слишком сложное, чтобы его можно было установить только одним значением атрибута. Вместо этого следует положиться на синтаксис "свойство-элемент". И, наконец, можно заполнить коллекцию GradientStops серией объектов GradientStop. Каждый объект GradientStop имеет свойства Offset и Color. Указать эти два значения можно с помощью обычного синтаксиса "свойство-элемент". Результат:

Использование сложных свойств XAML

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

Пройди тесты
Лучший чат для C# программистов