Fesselspiele Data Binding in WPF und Silverlight Rainer Stropek cubido business solutions gmbh Fesselspiele Data Binding in WPF und Silverlight
Ziele Grundlagen von Data Binding in WPF und Silverlight Erklärung von Data Binding Szenarien anhand von typischen Anwendungsfällen Hinweise auf Unterschiede bei Data Binding zwischen WPF und Silverlight Rainer Stropek, cubido business solutions gmbh
Einfaches Data Binding mit und ohne Dependency Properties Beispiel 1 Einfaches Data Binding mit und ohne Dependency Properties Rainer Stropek, cubido business solutions gmbh
Grundlagen Rainer Stropek, cubido business solutions gmbh public class Competitor { public string FirstName { get; set; } public string LastName { get; set; } } .property instance string FirstName { .get instance string MyApp.Competitor::get_FirstName() .set instance void MyApp.Competitor::set_FirstName(string) } Rainer Stropek, cubido business solutions gmbh
Grundlagen Erstellen eines Bindings {Binding…} Markup Extension Binding Klasse {StaticResource…} Markup Extension zum Zugriff auf Ressourcen Rainer Stropek, cubido business solutions gmbh
Einfaches Data Binding <Window.Resources> <local:Competitor x:Key="MyCompetitor" FirstName="Benjamin" LastName="Raich" /> </Window.Resources> <StackPanel> <TextBox Text="{Binding Source={StaticResource MyCompetitor}, Path=FirstName}" x:Name="FirstNameTextBox" /> <TextBox Text="{Binding Source={StaticResource MyCompetitor}, Path=LastName}" x:Name="LastNameTextBox" /> <StackPanel Orientation="Horizontal"> <TextBlock Text="Competitor:" /> <TextBlock Text="{Binding ElementName=FirstNameTextBox, Path=Text}" /> <TextBlock Text="{Binding ElementName=LastNameTextBox, Path=Text}" /> </StackPanel> <Button Click="Button_Click">Show Competitor</Button> <Button Click="Button_Click_1">Change Competitor</Button> Rainer Stropek, cubido business solutions gmbh
Grundlagen Rainer Stropek, cubido business solutions gmbh
Grundlagen Geschäftsobjekt Hermann Rainer TextBox TextBlock Text wird im Code verändert Geschäftsobjekt Änderung des Properties wird nicht erkannt! Hermann Rainer TextBox TextBlock Geschäftsobjekt Hermann Hermann Rainer Hermann TextBox TextBlock Rainer Hermann Rainer Hermann Text wird verändert Rainer Stropek, cubido business solutions gmbh
Grundlagen Lösungen des Problems: Dependency Property Implementieren von INotifyPropertyChanged Rainer Stropek, cubido business solutions gmbh
Dependency Property Rainer Stropek, cubido business solutions gmbh public class Competitor : DependencyObject { public string FirstName get { return (string)GetValue(FirstNameProperty); } set { SetValue(FirstNameProperty, value); } } public static readonly DependencyProperty FirstNameProperty = DependencyProperty.Register("FirstName", typeof(string), typeof(Competitor), new UIPropertyMetadata(String.Empty)); public string LastName get { return (string)GetValue(LastNameProperty); } set { SetValue(LastNameProperty, value); } public static readonly DependencyProperty LastNameProperty = DependencyProperty.Register("LastName", typeof(string), Rainer Stropek, cubido business solutions gmbh
WPF übernimmt Verwaltung der Propertywerte Grundlagen WPF übernimmt Verwaltung der Propertywerte Rainer Stropek, cubido business solutions gmbh
Grundlagen Nahezu alle Properties in WPF sind als Dependency Properties implementiert Rainer Stropek, cubido business solutions gmbh
Grundlagen Rainer Stropek, cubido business solutions gmbh
Animationsbeispiel Rainer Stropek, cubido business solutions gmbh <Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="*"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <Canvas Grid.Row="0"> <Image Canvas.Top="0" Canvas.Left="0" Width="500" Source="..\Schillerfalter.jpg"/> Source="..\Schmetterling.jpg"> <Image.OpacityMask> <LinearGradientBrush> <GradientStop x:Name="OpacityTransparent" Color="#FF000000" Offset="1" /> <GradientStop x:Name="OpacityNonTransparent" Color="#00000000" </LinearGradientBrush> </Image.OpacityMask> </Image> </Canvas> <Button Grid.Row="1"> <Button.Triggers> <EventTrigger RoutedEvent="Button.Click"> <BeginStoryboard> <Storyboard> <DoubleAnimation Storyboard.TargetName="OpacityTransparent" Storyboard.TargetProperty="Offset" From="1" To="0" Duration="0:0:2"/> <DoubleAnimation Storyboard.TargetName="OpacityNonTransparent" From="1" To="0" Duration="0:0:2" BeginTime="0:0:0.5"/> </Storyboard> </BeginStoryboard> </EventTrigger> </Button.Triggers> Next Picture </Button> </Grid> </Page> Rainer Stropek, cubido business solutions gmbh
Grundlagen Rainer Stropek, cubido business solutions gmbh
Einfaches Data Binding Tipp: DataContext statt Source oder ElementName! public MyWindow() { InitializeComponent(); this.DataContext = new Competitor { FirstName = "Benjamin", LastName = "Raich" }; } <StackPanel> <TextBox Text="{Binding Path=FirstName}" x:Name="FirstNameTextBox" /> <TextBox Text="{Binding Path=LastName}" x:Name="LastNameTextBox" /> <StackPanel Orientation="Horizontal"> <TextBlock Text="Competitor:" /> <TextBlock Text="{Binding Path=FirstName}" /> <TextBlock Text="{Binding Path=LastName}" /> </StackPanel> <Button Click="Button_Click">Show Competitor</Button> <Button Click="Button_Click_1">Change Competitor</Button> Rainer Stropek, cubido business solutions gmbh
Data Binding und Collections Beispiel 2 Data Binding und Collections Rainer Stropek, cubido business solutions gmbh
ItemsControl Klasse Binden der Collection an das Property ItemsSource Tipp: Steuern Sie das Aussehen der einzelnen Items über ein Data Template! Rainer Stropek, cubido business solutions gmbh
Binden an ItemsSource Rainer Stropek, cubido business solutions gmbh public MyWindow() { InitializeComponent(); this.DataContext = new List<Competitor>() { new Competitor() { FirstName = "Hermann", LastName = "Mayer" }, { FirstName = "Benjamin", LastName = "Raich" } }; } Template Binding <ComboBox ItemsSource="{Binding}"> <ComboBox.ItemTemplate> <DataTemplate DataType="{x:Type local:Competitor}"> <StackPanel Orientation="Horizontal"> <TextBlock Text="Competitor:" /> <TextBlock Text="{Binding Path=FirstName}" /> <TextBlock Text="{Binding Path=LastName}" /> </StackPanel> </DataTemplate> </ComboBox.ItemTemplate> </ComboBox> Rainer Stropek, cubido business solutions gmbh
ComboBox und ListBox nutzen gleiches Template Binden an ItemsSource <Window.Resources> <DataTemplate DataType="{x:Type local:Competitor}"> <StackPanel Orientation="Horizontal"> <TextBlock Text="Competitor:" /> <TextBlock Text="{Binding Path=FirstName}" /> <TextBlock Text="{Binding Path=LastName}" /> </StackPanel> </DataTemplate> </Window.Resources> <StackPanel> … <ComboBox ItemsSource="{Binding}" /> <ListBox ItemsSource="{Binding}" /> Tipp: Legen Sie Data Templates zentral in den Ressourcen ab (Window.Resources oder App.xaml) ComboBox und ListBox nutzen gleiches Template Rainer Stropek, cubido business solutions gmbh
Binden an ItemsSource Collection Hermann, Mario Hermann ListBox Element wird im Code hinzugefügt Collection Änderung der Collection wird nicht erkannt! Hermann, Mario Hermann ListBox Hermann Implementiert INotifyCollectionChanged public MyWindow() { InitializeComponent(); this.DataContext = new ObservableCollection<Competitor>() { new Competitor() { FirstName = "Hermann", LastName = "Mayer" }, { FirstName = "Benjamin", LastName = "Raich" } }; } Rainer Stropek, cubido business solutions gmbh
Data Binding und Linq (Entity Framework) Beispiel 3 Data Binding und Linq (Entity Framework) Rainer Stropek, cubido business solutions gmbh
Beispielanwendung Rainer Stropek, cubido business solutions gmbh
Hands-on Lab Create a new WPF Application named SkiResults Add Folder Data Add Entity Model SkiEventModel in Folder Data Model Namespace is SkiResults.Data Rainer Stropek, cubido business solutions gmbh
Linq und Data Binding Competitor System.Data. Objects. DataClasses Linq-Klassen sind für Nutzung mit Data Binding vorbereitet EntityObject StructuralObject INotifyPropertyChanged Rainer Stropek, cubido business solutions gmbh
Hands-on Lab Basis-Grid zum Window hinzufügen <Grid Margin="10"> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <ComboBox Name="EventComboBox" Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0" Margin="0,0,0,10" /> <Button Name="SaveButton" Content="Save" Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="2" Margin="0,10,0,0"> </Button> </Grid> Rainer Stropek, cubido business solutions gmbh
Hands-on Lab Data Template in App.xaml definieren <DataTemplate DataType="{x:Type data:Event}"> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding Path=EventName}" /> <TextBlock Text=" (" /> <TextBlock Text="{Binding Path=Date}" /> <TextBlock Text=")" /> </StackPanel> </DataTemplate> Rainer Stropek, cubido business solutions gmbh
Linq und Data Binding private SkiEventEntities Context { get; set; } public Window1() { InitializeComponent(); this.Context = new SkiEventEntities(); this.DataContext = this.Context.Event.Include("Competitor"). OrderBy(e => e.EventName); } Linq-Query wird direkt an ComboBox gebunden … <ComboBox Name="EventComboBox" ItemsSource="{Binding}" Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0" Margin="0,0,0,10" /> Tipp: Immer Geschäftsobjekte binden, nie Umweg über Strings gehen! Rainer Stropek, cubido business solutions gmbh
Master-Detail Bindings Beispiel 4 Master-Detail Bindings Rainer Stropek, cubido business solutions gmbh
Master-Detail Binding Selektion = Filter für untere Liste Aktuelle Auswahl = Filter Rainer Stropek, cubido business solutions gmbh
Hands-on Lab Data Template in App.xaml definieren <DataTemplate DataType="{x:Type data:Competitor}"> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding Path=Bib}" /> <TextBlock Text=". " /> <TextBlock Text="{Binding Path=Firstname}" /> <TextBlock Text=" " /> <TextBlock Text="{Binding Path=Lastname}" /> </StackPanel> </DataTemplate> Rainer Stropek, cubido business solutions gmbh
Master-Detail Binding Tipp: Mit UpdateSourceTrigger Zeitpunkt der Aktualisierung des Bindings steuern {Binding …, UpdateSourceTrigger=PropertyChanged} … <ComboBox Name="EventComboBox" ItemsSource="{Binding}" Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0" Margin="0,0,0,10" IsSynchronizedWithCurrentItem="True" /> <ListBox Name="CompetitorListBox" ItemsSource="{Binding Path=Competitor}" Grid.Column="0" Grid.Row="1" Margin="0,0,10,0" IsSynchronizedWithCurrentItem="True" /> Rainer Stropek, cubido business solutions gmbh
Hands-on Lab Rainer Stropek, cubido business solutions gmbh <Grid Grid.Column="1" Grid.Row="1" DataContext="{Binding Path=Competitor}"> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <TextBlock Grid.Column="0" Grid.Row="0" Text="Bib" Margin="0,0,10,0" /> <TextBox Grid.Column="1" Grid.Row="0" Text="{Binding Path=Bib, Mode=TwoWay}" /> <TextBlock Grid.Column="0" Grid.Row="1" Text="Fis code" Margin="0,0,10,0" /> <TextBox Grid.Column="1" Grid.Row="1" Text="{Binding Path=FisCode, Mode=TwoWay}" /> <TextBlock Grid.Column="0" Grid.Row="2" Text="Firstname" Margin="0,0,10,0" /> <TextBox Grid.Column="1" Grid.Row="2" Text="{Binding Path=Firstname, Mode=TwoWay}" /> <TextBlock Grid.Column="0" Grid.Row="3" Text="Lastname" Margin="0,0,10,0" /> <TextBox Grid.Column="1" Grid.Row="3" Text="{Binding Path=Lastname, Mode=TwoWay}" /> <TextBlock Grid.Column="0" Grid.Row="4" Text="Year of birth" Margin="0,0,10,0" /> <TextBox Grid.Column="1" Grid.Row="4" Text="{Binding Path=YearOfBirth, Mode=TwoWay}" /> <TextBlock Grid.Column="0" Grid.Row="5" Text="Nation" Margin="0,0,10,0" /> <TextBox Grid.Column="1" Grid.Row="5" Text="{Binding Path=Nation, Mode=TwoWay}" /> <TextBlock Grid.Column="0" Grid.Row="6" Text="Ski" Margin="0,0,10,0" /> <TextBox Grid.Column="1" Grid.Row="6" Text="{Binding Path=Ski, Mode=TwoWay}" /> <TextBlock Grid.Column="0" Grid.Row="7" Text="Total time" Margin="0,0,10,0" /> <TextBox Name="TotalTimeTextBox" Grid.Column="1" Grid.Row="7" Text="{Binding Path=TotalTime, Mode=TwoWay}" /> </Grid> Rainer Stropek, cubido business solutions gmbh
Änderungen in DB zurückschreiben Beispiel 5 Änderungen in DB zurückschreiben Rainer Stropek, cubido business solutions gmbh
Master-Detail Binding … protected override void OnInitialized(EventArgs e) { base.OnInitialized(e); this.SaveButton.Click += new RoutedEventHandler(this.SaveButton_Click); } private void SaveButton_Click(object sender, RoutedEventArgs e) this.entities.SaveChanges(); Alles andere erledigt Data Binding! Rainer Stropek, cubido business solutions gmbh
Beispiel 6 Converter Rainer Stropek, cubido business solutions gmbh
Formatieren oder Umwandeln von Daten im Binding Standardverhalten: ToString() Rainer Stropek, cubido business solutions gmbh
Hands-on Lab Neuen Ordner Converter anlegen TimeToStringConverter in Projekt erstellen Kopieren von 010 – TimeToStringConverter TimeToStringConverter in App.xaml anlegen Rainer Stropek, cubido business solutions gmbh
Converter Rainer Stropek, cubido business solutions gmbh public class TimeToStringConverter : IValueConverter { public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture) { … } public object ConvertBack(object value, System.Type targetType, } … <TextBox Name="TotalTimeTextBox" Grid.Column="1" Grid.Row="7" Text="{Binding Path=TotalTime, Mode=TwoWay, Converter={StaticResource TimeToStringConverter}}" /> Rainer Stropek, cubido business solutions gmbh
Gültigkeitsprüfungen Beispiel 7 Gültigkeitsprüfungen Rainer Stropek, cubido business solutions gmbh
Hands-on Lab Neuen Ordner Converter anlegen TimeToStringConverter in Projekt erweitern Kopieren von 020 - TimeToStringConverter with Validation TextBox um Validierung erweitern Textbaustein dafür verwenden Rainer Stropek, cubido business solutions gmbh
Tipp: Converter und Gültigkeitsprüfung in einer Klasse zusammenfassen public class TimeToStringConverter : ValidationRule, IValueConverter { public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture) { … } public object ConvertBack(object value, System.Type targetType, public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo) { … } } Tipp: Converter und Gültigkeitsprüfung in einer Klasse zusammenfassen … <TextBox Name="TotalTimeTextBox" Grid.Column="1" Grid.Row="7"> <TextBox.Text> <Binding Path="TotalTime" Mode="TwoWay" Converter="{StaticResource TimeToStringConverter}"> <Binding.ValidationRules> <ExceptionValidationRule /> </Binding.ValidationRules> </Binding> </TextBox.Text> </TextBox> Rainer Stropek, cubido business solutions gmbh
Tipp: Schreibweise kann drastisch verkürzt werden! Gültigkeitsprüfung Tipp: Schreibweise kann drastisch verkürzt werden! … <TextBox Name="TotalTimeTextBox" Grid.Column="1" Grid.Row="7"> <TextBox.Text> <Binding Path="TotalTime" Mode="TwoWay" Converter="{StaticResource TimeToStringConverter}"> <Binding.ValidationRules> <ExceptionValidationRule /> </Binding.ValidationRules> </Binding> </TextBox.Text> </TextBox> … <TextBox Name="TotalTimeTextBox" Grid.Column="1" Grid.Row="7"> <TextBox.Text> <Binding Path="TotalTime" Mode="TwoWay" Converter="{StaticResource TimeToStringConverter}“ ValidatesOnExceptions="True" /> </TextBox.Text> </TextBox> … <TextBox Name="TotalTimeTextBox" Grid.Column="1" Grid.Row="7" Text="{Binding Path=TotalTime, Mode=TwoWay, Converter={StaticResource TimeToStringConverter}, ValidatesOnExceptions=True}" /> Rainer Stropek, cubido business solutions gmbh
Button bleibt trotz Validierungsfehler aktiv Gültigkeitsprüfung Button bleibt trotz Validierungsfehler aktiv Rainer Stropek, cubido business solutions gmbh
Gültigkeitsprüfung public class IsEnabledConverter : IMultiValueConverter { public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) { … } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, } Tipp: Als Multi-Value Converter implementieren, um mehrere Quell-Controls zu unterstützen … <Button Name="SaveButton" Content="Save" Grid.Column="0" Grid.ColumnSpan="2“ Grid.Row="2" Margin="0,10,0,0"> <Button.IsEnabled> <MultiBinding Converter="{StaticResource IsEnabledConverter}"> <Binding ElementName="TotalTimeTextBox" Path="(Validation.Errors).Count" /> <!-- Here you can enter additional validations --> </MultiBinding> </Button.IsEnabled> </Button> Rainer Stropek, cubido business solutions gmbh
Data Binding über Control-Grenzen hinweg Beispiel 8 Data Binding über Control-Grenzen hinweg Rainer Stropek, cubido business solutions gmbh
Hands-on Lab Detailgrid in eigenes User Control ausgliedern DataContext in User Control entfernen Namespace in Main Window setzen User Control statt Detailgrid einfügen Validierung bei Save-Button auskommentieren (dafür müsste etwas mehr gemacht werden) Rainer Stropek, cubido business solutions gmbh
Data Binding und User Controls <Window x:Class="SkiResults.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:SkiResults" Title="Window1" Height="500" Width="500"> … <local:Details x:Name="DetailsForm" Grid.Column="1" Grid.Row="1" DataContext="{Binding Path=Competitor}" /> </Window> Tipp: Auch bei User Controls mit Data Context arbeiten; wird auch in diesem Fall vererbt! Rainer Stropek, cubido business solutions gmbh
Data Binding Unterschiede Silverlight und WPF Data Binding in Silverlight funktioniert grundsätzlich so wie in WPF Viele Einschränkungen IsSynchronizedWithCurrentItem gibt es nicht Dependency Properties alleine reichen nicht für automatisches Update; INotifyPropertyChanged muss implementiert werden Viele, viele weitere Kleinigkeiten Vorsicht mit der Performance! Rainer Stropek, cubido business solutions gmbh
Was wir nicht behandelt haben… Bindings in Control Templates RelativeSource Bindings Anpassung des Fehlerhinweises bei Validierung Rainer Stropek, cubido business solutions gmbh
Lust auf mehr? Bücher Entwickler Akademie WPF und XAML Programmierhandbuch XAML Kurz & Schnell Entwickler Akademie C# Fundamentals C# 3.5 Upgrade Datenorientierte Anwendungen mit WPF und Silverlight Rainer Stropek, cubido business solutions gmbh
Fragen an r.stropek@cubido.at Vielen Dank für‘s Kommen! Fragen an r.stropek@cubido.at Rainer Stropek, cubido business solutions gmbh