Artykuł

freeimages.com freeimages.com
paź 22 2015
0

Biblioteki warte poznania w C# - Conditional XAML

W swojej stosunkowo krótkiej karierze programistycznej, zdążyłem już pracować z różnymi technologiami. Naturalnym tego następstwem są oczywiście wszelkiej maści porównania. Czasem np. porównuje Razora z MVC do XAMLa. I choć w teorii bardziej rozbudowana jest ta druga z obu tych technologii, to w praktyce Razor ma kilka konstrukcji, do których tęsknym okiem wyglądają designerzy XAMLa. Jedną z nich jest IF. I choć w teorii można ją częściowo zastąpić choćby za pomocą VisualStates, to w praktyce okazuje się, że istniejące rozwiązania, nie zawsze są do końca optymalne, ale od czego są dodatkowe biblioteki;-) Powitajcie Conditional XAML - prostą bibliotekę, która skrywa olbrzymie możliwości.

Charakterystyka i zastosowanie

Conditional XAML to stosunkowo nie duża biblioteka napisana przez francuskiego programistę Samuela Blancharda i z założenia wprowadza ona częściową implementację instrukcji warunkowych do XAMLa.

Tytułowa biblioteka umożliwia nam tworzenie instrukcji warunkowych, które będą pasować do następujących grup:

  • BooleanCondition
  • DoubleCondition
  • StringCondition
  • DateTimeCondition
  • DateTimeOffsetCondition
  • TimeSpanCondition
  • ScreenOrientationCondition
  • IsDesignTimeCondition

Większość z powyższych warunków działa podobnie. Musimy określić typ, rodzaj porównania (np. większe, mniejsze, równe itd.) oraz wskazać dwie wartości (możemy je bindować). Dla każdego z porównań, możemy zastosować konstrukcję If-Else. Nie ma konstrukcji ElseIf, ale można ją zasymulować tworząc po sobie x różnych warunków If (bez Else).

Biblioteka daje naprawdę niezłe możliwości, aczkolwiek ma jedną zasadniczą wadę - bindowane wartości nie odświeżają się do momentu przerysowania widoku (kod XAML, który nie pasuje do warunku nie wykonuje się wcale), dlatego też potencjalne odświeżenie możemy uzyskać dopiero np. przy zmianie orientacji ekranu, bądź też ręcznym przerysowaniu elementów.

Kiedy warto zastosować bibliotekę Conditional XAML

Bibliotekę warto stosować wszędzie tam, gdzie standardowe rozwiązania nie mają racji bytu. Ja np. wykorzystałem ją w projekcie, który obecnie tworzę zawodowo do wyrysowania różnego rodzaju kafelków. W momencie gdy próbowałem do tego zadania zaprzęgnąć VisualStates, to mój kod umieszczony w poszczególnych stanach i tak się wykonywał (nie był jedynie wyświetlany), co prowadziło do sporego narzutu wydajności, a ponadto prowadziło do pobierania elementów, które w aktualnej chwili nie były potrzebne. Conditional XAML rozwiązał ten problem w fenomenalny sposób.

Przykład praktyczny

W przykładzie praktycznym stworzyłem bardzo prostą aplikację na Windows Phone. Byłem na tyle leniwy, że nie użyłem nawet MVVM. Bibliotekę ściągniecie oczywiście z Nugeta.

Zaczniemy od części code-behind strony MainPage:

public sealed partial class MainPage : Page
{
	public MainPage()
	{
		this.InitializeComponent();
		this.NavigationCacheMode = NavigationCacheMode.Required;
		this.ConfigurePage();
	}

	public bool TestBool { get; set; }

	public string StringValue { get; set; }

	private void ConfigurePage()
	{
		this.TestBool = true;
		this.StringValue = "Hello World";
		this.DataContext = this;
	}
}

Kluczowym elementem tego listingu, jest moment ustawienia kontekstu danych - jeśli tę linijkę kodu przenieślibyśmy wcześniej, to wszelkie instrukcje zapisane później, nie znalazłaby swojego odzwierciedlenia do momentu przerysowania strony (czyli np. zmiany orientacji) - warto wziąć to pod uwagę.

Poniżej kod samej strony:

<Page mc:Ignorable="d"
    x:Class="XamlConditional.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:XamlConditional"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:cond="using:SamuelBlanchard.Controls.Statements"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
    RequestedTheme="Light">

    <StackPanel Margin="19">
        <TextBlock Style="{StaticResource GroupHeaderTextBlockStyle}" Text="BooleanCondition" />
        <cond:Statement>
            <cond:If>
                <cond:BooleanCondition Value1="{Binding TestBool}"
                                       Operator="Equal" Value2="True" />
                <cond:If.Then>
                    <TextBlock Foreground="Blue" Style="{StaticResource GroupHeaderTextBlockStyle}">Blue</TextBlock>
                </cond:If.Then>
                <cond:If.Else>
                    <TextBlock Foreground="Red" Style="{StaticResource GroupHeaderTextBlockStyle}">Red</TextBlock>
                </cond:If.Else>
            </cond:If>
        </cond:Statement>
        <TextBlock Style="{StaticResource GroupHeaderTextBlockStyle}" Text="ScreenOrientationCondition" Margin="0,19,0,0" />
        <cond:Statement>
            <cond:If>
                <cond:ScreenOrientationCondition Orientation="IsPortraitNormal" />
                <cond:If.Then>
                    <TextBlock Foreground="Blue" Style="{StaticResource GroupHeaderTextBlockStyle}">Portrait</TextBlock>
                </cond:If.Then>
                <cond:If.Else>
                    <TextBlock Foreground="Red" Style="{StaticResource GroupHeaderTextBlockStyle}">Something else</TextBlock>
                </cond:If.Else>
            </cond:If>
        </cond:Statement>
        <TextBlock Style="{StaticResource GroupHeaderTextBlockStyle}" Text="StringCondition" Margin="0,19,0,0" />
        <cond:Statement>
            <cond:If>
                <cond:StringCondition Operator="Equal" Value1="{Binding StringValue}" Value2="Hello World" />
                <cond:If.Then>
                    <TextBlock Foreground="Blue" Style="{StaticResource GroupHeaderTextBlockStyle}">Hello World</TextBlock>
                </cond:If.Then>
                <cond:If.Else>
                    <TextBlock Foreground="Red" Style="{StaticResource GroupHeaderTextBlockStyle}">Goodbye World</TextBlock>
                </cond:If.Else>
            </cond:If>
        </cond:Statement>
    </StackPanel>
</Page>

Na pierwszy rzut oka, konstrukcje wydają się być trochę przerośnięte - szczególnie nadmiarowy wydaje się być znacznik Statement, ale jest to kwestia przyzwyczajenia. Zastosowałem tutaj trzy różne konstrukcje warunkowe - każda z nich sprawdza inne wyrażenie, a dwie z nich wykorzystują wartości przypisane w części code-behind. Jak widać, możemy się również zapinać na aktualną orientację ekranu. Poniżej screenshot przedstawiający działanie aplikacji w praktyce:

Podsumowanie

Conditional XAML to biblioteka, która pozytywnie zaskakuje, dodając funkcjonalność, której osobiście bardzo mi brakowało w XAMLu. Oczywiście wiele rozwiązań tej technologii pozwala obejść te ograniczenia, dlatego niekoniecznie zawsze powinniśmy iść na skróty, ale jest to ciekawe rozwiązanie, z którego warto skorzystać w pewnych nietypowych sytuacjach. Osobiście mam nadzieję, że autor będzie dalej rozwijał bibliotekę.

Metryka

Podoba Ci się ten wpis? Powiedz o tym innym!

Send to Kindle

Komentarze

blog comments powered by Disqus