poniedziałek, 11 czerwca 2012

Moje boje z "Binding" - źródła danych

Dziś mam zamiar opisać kolejne sposoby użycia "Binding"
Docelowo chciałbym opisać konkretne implementacje rozwiązań, których nie znajdziecie w dokumentacji, ale doszedłem do wniosku, że zanim przejdę do bardziej skomplikowanych rzeczy należałoby przedstawić podstawy.

Źródło danych dla "Binding" domyślnie jest ustawione na właściwość "DataContext", ale możemy oczywiście wybierać je według własnego upodobania, służą do tego właściwości takie jak:
Do kodów z poprzedniego wpisu dopisujemy nowe elementy, m.in. dodaje klasę ThreeStrings.
    public class ThreeStrings
    {
        public string Val1 {get;set;}
        public string Val2 { get; set; }
        public string Val3 { get; set; }
    }
Następnie inicjuję element tej klasy w pliku "MainWindow.xaml"
    <Window.Resources>
        <bnd:ThreeStrings x:Key="ts1" 
             Val1="Binding" 
             Val2="is" 
             Val3="great"/>
    </Window.Resources>
Powyższy zapis jest odpowiednikiem
    ThreeStrings ts1 = new ThreeStrings() 
        {
             Val1="Binding", 
             Val2="is", 
             Val3="great"
        };
Za pomocą zmiennej "ts1" możemy w "Binding'u" zdefiniować źródło danych.
    <TextBlock Text="{Binding Source={StaticResource ts1}, Path=Val1}"/>
"Source" wskazuję na statycznie zdefiniowany obiekt "ts1", a następnie za pomocą właściwości "Path" pobiera wartość z "Val1".
Gdybyśmy chcieli wyświetlić wszystkie 3 wartości zapisane w obiekcie "ts1" to możemy skorzystać z "MultiBinding'u" oraz jego właściwości "StringFormat".
        <TextBlock>
                <TextBlock.Text>
                    <MultiBinding  StringFormat="{}{0} {1} {2}!">
                        <Binding Source="{StaticResource ts1}" Path="Val1"/>
                        <Binding Source="{StaticResource ts1}" Path="Val2"/>
                        <Binding Source="{StaticResource ts1}" Path="Val3"/>
                    </MultiBinding>
                </TextBlock.Text>
        </TextBlock>
"StringFormat" ma działanie analogiczne do funkcji "Format" z klasy "string"tak więc nie będę się rozpisywał na jego temat.
"MultiBinding" natomiast jest odmiana "Binding'u" pozwalająca zgromadzić dane z różnych źródeł i połączyć je w obiekt wynikowy, bądź za pomocą "StringFormat", bądź za pomocą konwerterów (o czym następnym razem).

"RelativeSource" odpowiada za definiowanie źródła danych położonego względem obiektu, dla którego to źródło ustawiamy.
Możemy np. pobrać dane z przodka typu "Window", który ma dane zapisane w "DataContext".
   Content="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type Window}}, 
             Path=DataContext.Name}"
możemy też pobrać właściwości innych elementów np. "StackPanel'u".
   Content="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type StackPanel}}, 
             Path=Tag}
Więcej na temat określania relatywnego źródła danych można przeczytać tu.

Pozostało nam jeszcze określanie źródła danych za pomocą "ElementName", w takim wypadku podajemy jako parametr "ElementName" wartość zapisana jako "Name" w obiekcie który chcemy użyć jako źródło danych.
        <Button Name ="btn1" Content="{Binding Path=Name}" Height="23" HorizontalAlignment="Left" Width="200" />
        <Button Name ="btn6" Content="{Binding Path=Content,ElementName=btn1}" Height="23" HorizontalAlignment="Left" Width="200" />
W powyższym kodzie przycisk "btn6" wyświetli zawartość właściwości "Content" przycisku "btn1".

Za pomocą "ElementName" możemy zdefiniować, który element będzie miał ustawiony focus w momencie pokazania okna.
  
        FocusManager.FocusedElement ="{Binding ElementName=btn2}"

Poniżej zamieszczam kod zawierający zdefiniowane wcześniej przykłady.
  
    <Window x:Class="Binding.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:bnd="clr-namespace:Binding"
        FocusManager.FocusedElement ="{Binding ElementName=btn2}"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <bnd:ThreeStrings x:Key="ts1" Val1="Binding" Val2="is" Val3="great"/>
    </Window.Resources>
    <StackPanel Tag="Text placed in StackPanel Tag">
        <Button Name ="btn1" Content="{Binding Path=Name}" Height="23" HorizontalAlignment="Left" Width="200" />
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="{Binding Source={StaticResource ts1}, Path=Val1}"/>
            <TextBlock Text="{Binding Source={StaticResource ts1}, Path=Val2}"/>
            <TextBlock Text="{Binding Source={StaticResource ts1}, Path=Val3}"/>
        </StackPanel>
        <TextBlock>
                <TextBlock.Text>
                    <MultiBinding  StringFormat="{}{0} {1} {2}!">
                        <Binding Source="{StaticResource ts1}" Path="Val1"/>
                        <Binding Source="{StaticResource ts1}" Path="Val2"/>
                        <Binding Source="{StaticResource ts1}" Path="Val3"/>
                    </MultiBinding>
                </TextBlock.Text>
        </TextBlock>
        <Button Name ="btn2" Content="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type StackPanel}}, Path=Tag}" 
                Height="23" HorizontalAlignment="Left" Width="200" />
        <Button Name ="btn3" Content="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type Window}}, Path=DataContext.Name}" 
                Height="23" HorizontalAlignment="Left" Width="200" />

        <Button Name ="btn6" Content="{Binding Path=Content,ElementName=btn1}" 
                Height="23" HorizontalAlignment="Left" Width="200" />
    </StackPanel>
</Window>
Mam nadzieję, że nie tylko ja jestem pod wrażeniem możliwości "Binding'u". Następnym razem przejdę do konwerterów.

Brak komentarzy:

Prześlij komentarz