XAML.cz Magazín moderních technologií založených na XAML

Konvertor - nejlepší přítel člověka 1

Napsáno pro WPF od Tomáš Pastorek [30.03.2010]

Součástí WPF je propracovaný DataBinding (více ve článku DataBinding a DataTemplate), kterým je možné přiřazovat hodnoty z různých zdrojů dat (vlastnosti objektů, kolekce dat, apod.) v uživatelském rozhraní. Určitě vás napadne, že ne všechny zdroje a cíle jsou stejného typu. A máte samozřejmě pravdu. Také vás může napadnout, že je občas potřeba data nějakým způsobem upravit, než se dostanou ke svému cíli. Naštěstí existuje řešení: Ať na úpravu typu dat nebo na určitou datovou transformaci můžeme použít konvertor (Converter).

Co to tedy je? Konvertor (Converter) je třída zděděná z interface IValueConverter pro jednoduchý konvertor nebo z interface IMultiValueConverter pro transformace vyžadující více zdrojů dat. V dnešním dílu se budeme zabývat pouze jednoduchým konvertorem implementujícím interface IValueConverter. Tento interface obsahuje pouze dvě metody: Convert(...) pro převod ze zdroje do cíle a ConvertBack(...) pro převod z cíle do zdroje. Pro názornost je činnost konvertoru vysvětlena následujícím obrázkem:

converter1

 

Ve zkratce:

  • Jako cíl DataBindingu můžeme použít pouze Dependency Property (a tu může obsahovat pouze Dependency object). Stručně tento základní mechanismus popisuje článek Dependency Properties (EN).
  • Zdroj dat pro DataBinding může být libovolná vlastnost (Property) jakéhokoli objektu.
  • Mezi zdroj a cíl DataBindingu se vloží konvertor, který může data upravit.
  • Pro směr dat ze zdroje do cíle se používá metoda Convert(...)
  • Pro opačný směr se používá ConvertBack(...)

Příklad

Pro názornou ukázku jsem zvolil velmi jednoduchý příklad. Budeme chtít, aby se nějaký TextBox zneplatnil (IsEnabled = false), pokud je určitý CheckBox zaškrtnutý (IsChecked = true). Je zde vidět, proč pouze DataBinding nepomůže – je potřeba převést logiku zaškrtávání na opačnou hodnotu bool. Tedy něco jako: “value = !value”. Logika konvertoru je tedy velmi jednoduchá:

 

[System.Windows.Data.ValueConversion(typeof(bool), typeof(bool))]
public class InverseBoolConverter :  System.Windows.Data.IValueConverter
{

    public object Convert(object value, Type targetType, object parameter,
        System.Globalization.CultureInfo culture)
    {
        if (targetType != typeof(bool))
            throw new InvalidOperationException("Target is not a boolean.");

        return !(bool)value;
    }

    public object ConvertBack(object value, Type targetType, object parameter,
        System.Globalization.CultureInfo culture)
    {
        // pouze převod ze zdroje do cíle
        throw new NotSupportedException();
    }
}

 

Ke kódu jenom pár poznámek:

  • ValueConversionAttribute nemá na implementaci žádný vliv a slouží pouze pro vývojové nástroje, které mohou konvertor najít podle daných zdrojových a cílových typů. Konvertor bude fungovat i bez tohoto atributu.
  • Protože při psaní XAMLu neprobíhá silně typová kontrola, je dobré ošetřit typy dat na vstupu konvertoru.

 

Po vytvoření konvertoru jej musíme nadefinovat v sekci Resources, abychom ho mohli dále použít. Pokud bychom chtěli konvertor používat v rámci celého elementu(objektu) Window, bude definice vypadat takto:

<Window.Resources>
     <local:InverseBoolConverter x:Key="InverseConverter" />
</Window.Resources>

Pokud bychom chtěli nyní použít vytvořenou instanci naší třídy InverseBoolConverter stačí se na ni odkázat pomocí jména a markup extension StaticResource - {StaticResource InverseConverter}.

Celý kód v XAMLu:

<Window x:Class="ConverterTest.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:ConverterTest"
    Title="Converter Test - Xaml.cz" Height="300" Width="300">
    <Window.Resources>
        <local:InverseBoolConverter x:Key="InverseConverter" />
    </Window.Resources>
    <StackPanel Margin="10">
        <CheckBox x:Name="check1" Content="Zaškrtni mě :)" Padding="10,0,0,10" />
        <TextBox MinLines="3" IsEnabled="{Binding ElementName=check1,Path=IsChecked,Converter={StaticResource InverseConverter}}">Textbox...</TextBox>
    </StackPanel>
</Window>

Zde je názorně vidět použití konvertoru: Vlastnost IsEnabled TextBoxu je provázána DataBindingem s vlastností IsChecked CheckBoxu, který je pojmenovaný “check1”. Mezi tuto vazbu se použil konvertor z přikladu pro otočení hodnoty bool, který je v sekci Resources nadefinován pod názvem “InverseConverter”.

 

Závěr

Možná z tohoto článku na první pohled nebyla zřejmá krása použití konvertoru pro tak jednoduchý příklad. Ale stačí, když tento InverseBoolConverter už jednou budeme mít v projektu a uvidíte, že se jeho použití najde vícekrát. A o elegantní znovupoužitelné řešení jde přece vždy. :)

Komentáře

ukládám komentář, vyčkejte prosím..
  1. Buďte první, kdo napíše komentář.

@xamlcz

  • RT @jvanrhyn: XAML, It's a bit like olives. Takes a while to get used to. But once you're used to it. It is actually pretty good. <3 XAML
  • RT @moser_christian: WPF Inspector 0.9.7 is released. It supports .NET 3.5 and 4.0 The project is now open source and available on CodeP ...
  • Jeff Handley oznámil vydání WCF RIA Services v.1.0 SP1 RTM http://bit.ly/gOgckn ke stažení na http://bit.ly/gVAXdK
  • jedna výzva pro Brno. Byl někdo z vás na přednášce o RIA v MS Akvárku? Dejte o sobě vědět. Děkuji
  • také jste uvažovali o tom, že zkusíte na projekt použít Caliburn Micro nebo naopak Prism 4? A co tak obojí, šlo by to nebo ne? Již brzy