piątek, 14 grudnia 2012

70-511 Rozdział 6 - Binding

Bindowanie to mechanizm wiążący dane z interfejsem je wyświetlającym. Mechanizm ten w WPF jest bardzo rozbudowany i oferuje możliwości nieosiągalne w prosty sposób dla Windows Forms.

Za proces bindowania odpowiada klasa Binding. Posiada ona następujące właściwości:
  • ElementName - nazwa element, który ma służyć jako źródło. Wykorzystujemy tę właściwość (zamiast Source) jeżeli bindujemy do elementu WPF (np. kontrolki)
  • FallbackValue - wartość w przypadku gdy bindowanie zawiedzie
  • Mode - kierunek przepływu danych
  • NotifyOnSourceUpdated - jeżeli jest ustawiona ta flaga zostaje wywołane zdarzenie TargetUpdated podczas aktualizacji wartości z źródła do celu
  • NotifyOnTargetUpdated - jeżeli jest ustawiona ta flaga zostaje wywołane zdarzenie TargetUpdated podczas aktualizacji wartości z celu do źródła
  • Path - nazwa właściwości, która jest źródłem danych
  • RelativeSource - bindowanie na podstawie położenia źródła w drzewie wizualnym
  • Source - źródło w przypadku gdy nie bindujemy do elementu graficznego WPF
  • TargetNullValue - wartość, gdy źródło jest niezainicjowane (null)
  • XPath - zapytanie XPath w przypadku danych pobieranych z pliku XML

W przypadku najprostszej składni bindowania mamy do czynienia z połączeniem:





Bindowanie do elementu WPF
Najprostszy ze scenariuszów. Przykładowe bindowanie może wystąpić pomiędzy kontrolkami TextBlock i Slider: chcemy aby wartość ustawiona na suwaku została wyświetlona w kontrolce TextBlock. Realizacja tego zadania sprowadza się do:

Code:
<Window x:Class="WpfExample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfExample"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <StackPanel Orientation="Vertical">
            <Slider Name="Slider" />
            <TextBlock Text="{Binding ElementName=Slider, Path=Value}"/>
        </StackPanel>
    </Grid>
</Window>

To samo możemy osiągnąć w kodzie C# - np jeżeli potrzebujemy tworzyć bindowanie dynamiczne:

Code:
            var binding = new Binding();
            binding.ElementName = "Slider";
            binding.Path = new PropertyPath("Value");
            TextBlock1.SetBinding(TextBlock.TextProperty, binding);

Usuwanie bindowania dynamiczne:

Code:
BindingOperations.ClearBinding(TextBlock1, TextBlock.TextProperty);



Bindowanie do obiektu
Jeżeli nie bindujemy do elementu WPF używamy właściwości Source.
Przykład:

Code:
namespace WPFExample2
{
    public class PersonClass
    {
        public string Name
        {
            get { return "Jan Kowalski"; }
        }
    }
}

Code:
<Window x:Class="WPFExample2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WPFExample2"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <local:PersonClass x:Key="obj"/>
    </Window.Resources>
    <Grid>
        <Button Content="{Binding Source={StaticResource obj}, Path=Name}" />
    </Grid>
</Window>




DataContext
Żeby nie trzeba było za każdym razem ustawiać właściwości Source, można skorzystać z właściwości DataContext. Możemy ją ustawić zarówno dla pojedynczego elementu WPF, jak i całego kontenera. Najczęściej wykonuje się przypisanie w konstruktorze danego okna/kontrolki, a następnie binduje do poszczególnych elementów interfejsu użytkownika.

Code:
using System.Windows;

namespace WPFExample2
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = new PersonClass();
        }
    }
}

Code:
<Window x:Class="WPFExample2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Button Content="{Binding Name}" />
    </Grid>
</Window>




RelativeSource
Umożliwia bindowanie do elementu względem elementu docelowego. Typ bindowania jest uzależniony od właściwości Mode:
  • FindAncestor - szuka elementu nadrzędnego; specyfikujemy AncestorType - typ elementu oraz AncestorLevel - ile poziomów do góry drzewa wizualnego ma zostać przeszukanych
  • PreviousData - pozwala na bindowanie do poprzedniego elementu w przypadku list
  • Self - binduje do samego siebie
  • TemplatedParent - odnosi się do elementu, dla którego jest tworzony szablon kontrolki
Przykład:

Code:
<Window x:Class="WPFExample2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525">
    <Grid Tag="Tekst grida...">
        <Button Content="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Grid, AncestorLevel=1}, Path=Tag}" />
    </Grid>
</Window>






Kierunek bindowania



Rysunek przedstawia możliwe kierunki bindowania danych:
  • Default - domyślny tryb; w zależności od właściwości jest ustawione w jedną stronę lub obie
  • OneTime - aktualizuje wartość jednokrotnie: albo podczas uruchomienia aplikacji lub po zmianie właściwości DataContext
  • OneWay - pobiera aktualną wartość z źródła, ale w przypadku zmiany w elemencie docelowym nie zmienia źródła
  • OneWayToSource - uaktualnia wartość źródła na podstawie wartości elementu docelowego; jeżeli wartość w źródle się zmieni nie będzie odzwierciedlona w elemencie docelowym
  • TwoWay - zmiany są odwzorowywane w obu kierunkach
Najczęściej wykorzystuje się tryb TwoWay lub OneWay.



UpdateSourceTrigger
Właściwość ta determinuje jak często jest uaktualniane źródło zbindowane z danymi w trybie trybie TwoWay bądź OneWayToSource. Możliwe wartości tej właściwości to:
  • Explicit - gdy zostanie wywołana metoda Binding.UpdateSource()
  • LostFocus - gdy kontrolka zbindowana ze źródłem straci aktywność
  • PropertyChanged - gdy właściwość elementu zmieni wartość
  • Default - w zależności od ustawień standardowych (najczęściej tryb PropertyChanged)

1 komentarz:

  1. "NotifyOnSourceUpdated - jeżeli jest ustawiona ta flaga zostaje wywołane zdarzenie TargetUpdated" - powinno być "SourceUpdated"

    OdpowiedzUsuń