Рейтинг@Mail.ru

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

Print Friendly, PDF & Email

Мы рассматривали такое мощное средство 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"
Предупреждение «Невозможно добавить экземпляр типа "Condition" в семейство типа "UIElementCollection". Допускаются только элементы типа "UIElement"»

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

Корректный вариант использования блока кода с расширением разметки XAML
Корректный вариант использования блока кода с расширением разметки 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).

Последнее изменениеПятница, 15 Декабрь 2017 17:48 Прочитано 1543 раз

Поделиться

Print Friendly, PDF & Email

Оставить комментарий

Убедитесь, что вы вводите (*) необходимую информацию, где нужно
HTML-коды запрещены