W poprzednim odcinku omówiony (pobieżnie) został mechanizm DataBindingu. Dziś powiemy sobie co robić, abyśmy mogli w trochę większym stopniu niż dotychczas kontrolować to w jaki sposób wyświetlamy nasze dane.

ValueConverters

Załóżmy, że na potrzeby tego wpisu mamy prostą klasę:

public class Device

{

    public bool Active { get; set; }

}

Oczywiście chcemy jej właściwość Active wyświetlić na UI i oczywiście posługujemy się bindingiem.

<CheckBox Content=”Active?” IsChecked=”{Binding Active}” /> 

(źródło danych ustawiamy za pomocą DataContext). Co jednak, gdy wartości tej nie chcemy wyświetlić za pomocą klasy CheckBox a np. obrazka? Z pomocą przychodzi nam ValueConverter. Oczywiście nie będziemy zmieniać naszej zaawansowanej logiki, aby zwracała obrazek. Napiszemy odpowiednią klasę.

public class BoolToImageConverter : IValueConverter

{

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)

    {

        if (targetType != typeof(ImageSource))

            throw new InvalidOperationException(“The target must be a ImageSource”);

 

        return (bool) value

                  ? new BitmapImage(new Uri(“Yes.png”, UriKind.Relative))

                  : new BitmapImage(new Uri(“No.png”, UriKind.Relative));

    }

 

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)

    {

        throw new NotSupportedException();

    }

}

Nasza klasa konwertera jest niezwykle prosta. Implementujemy interface IValueConverter i tworzymy implementację metod Convert oraz ConvertBack. W naszym przypadku udostępniamy tylko konwersją w jedną stronę. Na podstawie wartości parametru zwracamy odpowiedni obrazek. Dodatkowo nasz metoda mogłaby brać pod uwagę aktualną kulturę i wyświetlać obrazek w zależności od tej. Jak tego użyć?
Deklarujemy nasz konwerter:

<Window.Resources>

    <local:BoolToImageConverter x:Key=”BoolToImageConverter” />

Window.Resources>

A następnie używamy przy bindingu

<Image Source=”{Binding Path=Active, Converter={StaticResource BoolToImageConverter}}” Width=”20″ Height=”20″/>

Efekt końcowy?

Ładniutki plusik 🙂

Templatki

Wiele z kontrolek udostępnia możliwość zdefiniowana wyglądu danych, które prezentują. Robi się to za pomocą definiowania nowego wyglądu w tagu DataTemplate. Zobaczmy jak to działa na przykładzie klasy ListBox. Stwórzmy sobie klasę do przechowywania zdjęć wraz z ich nazwą:

public class File

{

    public string Name { get; set; }

    public string Path { get; set; }

}

oraz wypełnijmy ją jakimiś danymi

const string path = @”C:\Users\pawlos\Pictures\Sample Images\Nature”;

var files = from file in Directory.GetFiles(path, “*.jpg”)

            select new File() {Name = Path.GetFileName(file), Path = file};

a nasz ListBox zdefiniujemy następująco

<ListBox x:Name=”listbox”>

    <ListBox.ItemTemplate>

        <DataTemplate>

            <StackPanel>

                <Label Content=”{Binding Name}” />

                <Image Source=”{Binding Path}” Height=”50″ />

            StackPanel>

        DataTemplate>

    ListBox.ItemTemplate>

ListBox>

W efekcie dostaniemy ładnie wyświetlone zdjęcia wraz z nazwą odpowiadającego pliku

Na dziś tyle. Następnym razem będzie o walidacji podczas bindowania.