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.
Founder of Octal Solutions a .NET software house.
Passionate dev, blogger, occasionally speaker, one of the leaders of Wroc.NET user group. Microsoft MVP. Podcaster – Ostrapila.pl