Главная Новости

Можно ли использовать константы условной компиляции в XAML


Опубликовано: 24.08.2018

Мы рассматривали такое мощное средство Visual Studio как константы условной компиляции. Это средство позволяет, в зависимости от значения заданной константы, включать и исключать из исполняемого файла те или иные участки кода. А существует ли аналогичная возможность для разметки XAML?

Представьте, например, такой вариант:

#If DEBUG Then <TextBlock Text="Это сборка Debug" /> #Else <TextBlock Text="Это сборка Release" /> #End If

Это было бы удобно и здорово! Но, к сожалению, XAML не позволяет использовать такой вариант. Придётся немного схитрить.

Давайте рассмотрим такую задачу. Допустим, мы написали приложение, которое имеет две редакции: одна – для загрузки в интернет и общего доступа, а вторая – для личного использования. Пусти эти версии различаются несколькими элементами управления, видимость которых и будет определяться этой константой компиляции. Определим константу типа Boolean и назовём её WEBSITE . Присвоим ей значение True для сетевой версии, и False – для локальной:

WEBSITE=True

Воспользуемся таким понятием XAML, как расширение разметки ( markup extension ). Напишем класс расширения, который будет наследоваться от класса MarkupExtension . Этот класс будет иметь два свойства и один метод – ProvideValue(), возвращающий значение, которое мы будем далее использовать в своей разметке XAML. Возвращаемое значение будет зависеть от константы условной компиляции:

Imports System.Windows.Markup Namespace ConditionalXAML ''' <summary> ''' Расширение XAML для изменения разметки в зависимости от констант компиляции. ''' </summary> Public Class Condition Inherits MarkupExtension Public Property Website As New Object Public Property Local As New Object Public Overrides Function ProvideValue(serviceProvider As IServiceProvider) As Object #If WEBSITE Then Return Website #Else Return Local #End If End Function End Class End Namespace

В файле разметки, в разделе импорта, импортируем пространство имён, содержащее наш класс Condition() :

xmlns:Conditional="clr-namespace:RootNamespace.ConditionalXAML"

Здесь RootNamespace – это пространство имён вашего приложения.

Далее в коде XAML файла, в тех местах, где где нужно использовать разметку, зависящую от констант компиляции, мы напишем следующий код:

<Conditional:Condition> <Conditional:Condition.Website> <TextBlock Text="Hello Web" /> </Conditional:Condition.Website> <Conditional:Condition.Local> <TextBlock Text="Hello Local" /> </Conditional:Condition.Local> </Conditional:Condition>

Естественно, вместо элементов TextBlock из этого примера вы вставите свою разметку.

Примечание 1: контейнер для вставки

Вставлять блоки со своей «условной разметкой» желательно в элементы, являющиеся специализированными списками, наследуемыми от класса ItemsControl() . Это базовый класс для элементов управления, которые отображают коллекции каких-либо объектов. Иначе получим предупреждение «Невозможно добавить экземпляр типа "Condition" в семейство типа "UIElementCollection". Допускаются только элементы типа "UIElement"»:

Предупреждение «Невозможно добавить экземпляр типа "Condition" в семейство типа "UIElementCollection". Допускаются только элементы типа "UIElement"»

Такой проект скомпилируется и будет работать, несмотря на предупреждение компилятора. Но корректным вариантом будет, например, такой:

Корректный вариант использования блока кода с расширением разметки XAML

Как видно, мы вставили блок с той же самой разметкой, но поместили его внутрь контейнера ViewBox .

Визуальными элементами для отображения коллекций, являются, например, ListBox, TreeView, ViewBox, Menu и другие.

Примечание 2: использование всех вариантов константы условной компиляции

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

Однако даже если в Condition.Local никакой разметки нет, необходимо использовать оба условия – и Condition.Website , и Condition.Local . В противном случае в том месте, куда вставлен блок кода с условием, пропущенное условие будет отображено в GUI как визуальный элемент с текстом System.Object.ToString() (ведь наш класс ConditionalXAML.Condition возвратит объект Local в любом случае).

Чтобы этого не произошло, нужно вставить внутрь объекта Conditional:.Condition.Local какой-то пустой контейнер или блок текста со значением String.Empty() (на рисунке выше мы использовали пустой контейнер StackPanel ).

rss