Konvertor - nejlepší přítel člověka 1
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:
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