black belt xaml data binding - reflection it belt xaml...•xaml (silverlight, windows phone,...

Post on 10-Jul-2020

27 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Black Belt XAML Data

Binding

Fons Sonnemans

Trainer

@fonssonnemans

Reflection IT

Fons Sonnemans • In-company trainingen

– Programming Languages

• Visual C#, Visual Basic

– Platforms

• ASP.NET (Web Forms, MVC)

• XAML (Silverlight, Windows Phone, Windows 8, Blend)

– Databases

• SQL, SQL Server, Entity Framework

• www.reflectionit.nl

My Apps Windows 8

Windows Phone 7 & 8

Topics

• Data Binding

• GridView

Data Binding • Data binding is the process that establishes a connection, or binding, between the

UI and the business object which allows data to flow between the two

• Enable clean view/model separation and binding

– Change UI presentation without code-behind modifications

• Every binding has a source and a target

– Source is the business object

– Target is the UI element

• Binding Expressions can be one way or two way and supports validation &

converters

Binding class

Binding b = new Binding {

ElementName = "SliderFontSize",

Path = new PropertyPath("Value"),

};

textBlock1.SetBinding( TextBlock.FontSizeProperty, b);

<TextBlock Text="HelloWorld" FontSize="{Binding Path=Value, ElementName=SliderFontSize}" />

<TextBlock Text="HelloWorld"> <TextBlock.FontSize>

<Binding ElementName="SliderFontSize" Path="Value" />

</TextBlock.FontSize>

</TextBlock>

Binding Source

• Element to Element Binding

• StaticResource Binding

DependencyObject

DependencyProperty Binding Object

Value Converter

DependencyObject

DependencyProperty

Binding Target Binding Source

ElementName

DependencyObject

DependencyProperty Binding Object

Value Converter

CLR Object

Property

Binding Target Binding Source

Source

Binding Source

• DataContext Binding

• RelativeSource Binding

DependencyObject

DependencyProperty Binding Object

Value Converter

CLR Object

Property

Binding Target Binding Source

DependencyObject

DependencyProperty Binding Object

Value Converter

DependencyObject

DependencyProperty

Binding Target Binding Source

RelativeSource

Element to Element Binding

• Element binding is performed in the same manner as Data Binding

with one addition: the ElementName property. ElementName defines

the name of the binding source element.

• The following code snippet shows the basic syntax for element

binding.

<Grid> <Slider x:Name="slider" Value="40" Minimum="10" /> <TextBlock Text="{Binding Value, ElementName=slider}" FontSize="32"/> </Grid>

Element to Element Binding

Converters

<TextBox FontSize="64" Text="{Binding Value, ElementName=slider, Mode=TwoWay}" Visibility="{Binding IsChecked, Converter={StaticResource BooleanToVisibilityConverter}, ElementName=checkBox}"/> <Slider x:Name="slider" /> <CheckBox x:Name="checkBox" Content="CheckBox" />

Employee class • Public properties, not fields

namespace DataBindingDemo.Models { public class Employee { public string Name { get; set; } public double Salary { get; set; } public Employee() { } public Employee(string name, double salary) { this.Name = name; this.Salary = salary; } public void RaiseSalary(double percentage) { this.Salary += Salary * (percentage / 100); } } }

StaticResource Binding • Register xmlns:models

• models:Employee

– Class must have a public default (parameter less) constructor

<Page x:Class="DataBindingDemo.MainPage" IsTabStop="false" xmlns:models="using:DataBindingDemo.Models" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:DataBindingDemo" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Page.Resources> <models:Employee x:Key="emp1" Name="Fons" Salary="2000" /> </Page.Resources> <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}"> <TextBlock FontSize="40" Margin="100" Text="{Binding Name, Source={StaticResource emp1}}" /> </Grid> </Page>

StaticResource Binding

CLR DataContext Binding • Default!

– Used when a Binding has no Source, RelativeSource or ElementName

• DataContext is inherited from parent

<Page x:Class="DataBindingDemo.MainPage" IsTabStop="false" xmlns:models="using:DataBindingDemo.Models" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:DataBindingDemo" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Page.Resources> <models:Employee x:Key="emp1" Name="Fons" Salary="2000" /> </Page.Resources> <Grid DataContext="{StaticResource emp1}" Background="{StaticResource ApplicationPageBackgroundThemeBrush}"> <TextBlock FontSize="40" Margin="100" Text="{Binding Name}" /> <TextBlock FontSize="40" Margin="100,200" Text="{Binding Salary}" /> </Grid> </Page>

TwoWay DataBinding to CLR Object • Implement INotifyPropertyChanged and notify (raise) PropertyChanged event

class Employee : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) { var handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(propertyName)); } } private string _name; public string Name { get { return _name; } set { if (_name != value) { _name = value; OnPropertyChanged("Name"); } } } <Grid DataContext="{StaticResource emp1}"

Background="{StaticResource ApplicationPageBackgroundThemeBrush}"> <TextBox FontSize="40" Margin="100" Text="{Binding Name, Mode=TwoWay}" <TextBlock FontSize="40" Margin="100,200" Text="{Binding Name}" /> </Grid>

Binding to Collections • Works with any object that implements IEnumerable

– Arrays, Lists, Collections, etc.

• Bind to the ItemsSource of Data Controls – ItemsControl

– ListBox

– ComboBox

– ListView

– GridView

– FlipView

ItemSource <Page x:Class="DataBindingDemo.MainPage" IsTabStop="false" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:DataBindingDemo" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}"> <ListView Margin="50" x:Name="listEmployees" /> </Grid> </Page>

public sealed partial class MainPage : Page { public MainPage() { this.InitializeComponent(); var l = new List<Employee> { new Employee("Fons", 2000), new Employee("Jim", 4000), new Employee("Ellen", 3000), }; this.listEmployees.ItemsSource = l; }

ItemTemplate <ListView Margin="40" x:Name="listEmployees" > <ListView.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <TextBlock Width="100" FontSize="20" Text="{Binding Path=Name}" /> <TextBlock Width="100" FontSize="20" Text="{Binding Salary}" /> <TextBlock Width="100" FontSize="20" Text="{Binding Name.Length}" /> </StackPanel> </DataTemplate> </ListView.ItemTemplate> </ListView>

GridView

GridView •Tiles

•Different

Content

•Different

Sizes

•Grouping

•Semantic

Zoom

namespace PanoramaDemo.Models { class FeaturedApp { public string Name { get; set; } public string Price { get; set; } public string Color { get; set; } public string ImageUrl { get { return "http://lorempixel.com/300/150/sports/" + Name; } } } }

namespace PanoramaDemo.ViewModels { class MainViewModel { public List<FeaturedApp> Apps { get; set; } public MainViewModel() { this.Apps = new List<Models.FeaturedApp>() { new FeaturedApp { Name = "App1", Color = "#FF0000", Price = "Free" }, new FeaturedApp { Name = "App2", Color = "#00FF00", Price = "$1.69" }, new FeaturedApp { Name = "App3", Color = "#0000FF", Price = "Free" }, new FeaturedApp { Name = "App4", Color = "#FF00FF", Price = "$4.99" }, }; } } }

<Application x:Class="PanoramaDemo.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:vm="using:PanoramaDemo.ViewModels" xmlns:local="using:PanoramaDemo"> <Application.Resources> <ResourceDictionary> <vm:MainViewModel x:Name="MainViewModel1" /> <DataTemplate x:Name="FeaturedAppDataTemplate"> <Grid Width="300" Height="200"> <Image Source="{Binding ImageUrl}" VerticalAlignment="Top" /> <StackPanel Background="{Binding Color}" Height="50" VerticalAlignment="Bottom"> <TextBlock Text="{Binding Name}" Margin="10,3" Foreground="White" FontWeight="Bold" /> <TextBlock Text="{Binding Price}" Margin="10,0" Foreground="White" /> </StackPanel> </Grid> </DataTemplate> </ResourceDictionary> </Application.Resources> </Application>

<GridView Grid.RowSpan="2" ItemTemplate="{StaticResource FeaturedAppDataTemplate}" ItemsSource="{Binding Apps}" SelectionMode="None" Padding="116,137,40,46" />

GridView •Tiles

•Different

Content

•Different

Sizes

•Grouping

•Semantic

Zoom

abstract class MenuItem { public string Name { get; set; } } class NavigationItem : MenuItem { public Type Page { get; set; } } class FeaturedApp : MenuItem { public string Price { get; set; } public string Color { get; set; } public string ImageUrl { get { return "http://lorempixel.com/300/150/sports/" + Name; } } }

class MainViewModel { public List<MenuItem> Items { get; set; } public MainViewModel() { this.Items = new List<MenuItem>() { new FeaturedApp { Name = "App1", Color = "#FF0000", Price = "Free" }, new FeaturedApp { Name = "App2", Color = "#00FF00", Price = "$1.69" }, new FeaturedApp { Name = "App3", Color = "#0000FF", Price = "Free" }, new FeaturedApp { Name = "App4", Color = "#FF00FF", Price = "$4.99" }, new NavigationItem { Name = "Free Apps" }, new NavigationItem { Name = "Paid Apps" }, }; } }

namespace PanoramaDemo.Selectors { class MenuItemDataTemplateSelector : DataTemplateSelector { protected override DataTemplate SelectTemplateCore(object item, DependencyObject container) { if (item is Models.FeaturedApp) { return App.Current.Resources["FeaturedAppDataTemplate"] as DataTemplate; } else { return App.Current.Resources["NavigationItemDataTemplate"] as DataTemplate; } } } }

<GridView Grid.RowSpan="2" ItemsSource="{Binding Items}" ItemTemplateSelector="{StaticResource MenuItemDataTemplateSelector1}" SelectionMode="None" Padding="116,137,40,46"> <GridView.ItemContainerStyle> <Style TargetType="GridViewItem"> <Setter Property="VerticalContentAlignment" Value="Stretch" /> <Setter Property="HorizontalContentAlignment" Value="Stretch" /> </Style> </GridView.ItemContainerStyle> </GridView>

<sel:MenuItemDataTemplateSelector x:Name="MenuItemDataTemplateSelector1" /> <DataTemplate x:Name="NavigationItemDataTemplate"> <Grid Background="Orange" Width="300" Height="200"> <TextBlock Text="{Binding Name}" Foreground="White" FontSize="32" Margin="10" /> </Grid> </DataTemplate> <DataTemplate x:Name="FeaturedAppDataTemplate"> <Grid Width="300" Height="200"> <Image Source="{Binding ImageUrl}" VerticalAlignment="Top" /> <StackPanel Background="{Binding Color}" Height="50" VerticalAlignment="Bottom"> <TextBlock Text="{Binding Name}" Margin="10,3" Foreground="White" FontWeight="Bold" /> <TextBlock Text="{Binding Price}" Margin="10,0" Foreground="White" /> </StackPanel> </Grid> </DataTemplate>

GridView •Tiles

•Different

Content

•Different

Sizes

•Grouping

•Semantic

Zoom

class FeaturedApp : MenuItem { public string Price { get; set; } public string Color { get; set; } public int RowSpan { get; set; } public FeaturedApp() { this.RowSpan = 1; } public string ImageUrl { get { if (RowSpan == 2) { return "http://lorempixel.com/300/360/sports/" + Name; } return "http://lorempixel.com/300/150/sports/" + Name; } } }

public MainViewModel() { this.Items = new List<MenuItem>() { new FeaturedApp { Name = "App1", Color = "#FF0000", Price = "Free" }, new FeaturedApp { Name = "App2", Color = "#00FF00", Price = "$1.69" }, new FeaturedApp { Name = "App3", Color = "#0000FF", Price = "Free", RowSpan = 2 }, new FeaturedApp { Name = "App4", Color = "#FF00FF", Price = "$4.99" }, new NavigationItem { Name = "Free Apps" }, new NavigationItem { Name = "Paid Apps" }, }; }

<!-- Remove Grid.Width and Grid.Height--> <DataTemplate x:Name="NavigationItemDataTemplate"> <Grid Background="Orange"> <TextBlock Text="{Binding Name}" Foreground="White" FontSize="32" Margin="10" /> </Grid> </DataTemplate> <DataTemplate x:Name="FeaturedAppDataTemplate"> <Grid> <Image Source="{Binding ImageUrl}" VerticalAlignment="Top" /> ...

class MenuItemDataTemplateSelector : DataTemplateSelector { protected override DataTemplate SelectTemplateCore(object item, DependencyObject container) { if (item is Models.FeaturedApp) { VariableSizedWrapGrid.SetRowSpan(container as UIElement, (item as Models.FeaturedApp).RowSpan); return App.Current.Resources["FeaturedAppDataTemplate"] as DataTemplate; } else { return App.Current.Resources["NavigationItemDataTemplate"] as DataTemplate; } } }

<GridView Grid.RowSpan="2" ItemsSource="{Binding Items}" ItemTemplateSelector="{StaticResource MenuItemDataTemplateSelector1}" SelectionMode="None" Padding="116,137,40,46"> <GridView.ItemContainerStyle> <Style TargetType="GridViewItem"> <Setter Property="VerticalContentAlignment" Value="Stretch" /> <Setter Property="HorizontalContentAlignment" Value="Stretch" /> </Style> </GridView.ItemContainerStyle> <GridView.ItemsPanel> <ItemsPanelTemplate> <VariableSizedWrapGrid ItemWidth="300" ItemHeight="200" /> </ItemsPanelTemplate> </GridView.ItemsPanel> </GridView>

GridView •Tiles

•Different

Content

•Different

Sizes

•Grouping

•Semantic

Zoom

class MainViewModel { public List<MenuGroup> Groups { get; set; } public MainViewModel() { this.Groups = new List<MenuGroup>() { new MenuGroup { Title = "Spotlight", Items = new List<MenuItem> { new FeaturedApp { Name = "App1", Color = "#FF0000", Price = "Free" }, new FeaturedApp { Name = "App2", Color = "#00FF00", Price = "$1.69" }, new FeaturedApp { Name = "App3", Color = "#0000FF", Price = "Free", RowSpan = 2 }, new FeaturedApp { Name = "App4", Color = "#FF00FF", Price = "$4.99" }, new NavigationItem { Name = "Free Apps" }, new NavigationItem { Name = "Paid Apps" }, } }, new MenuGroup { Title = "Games", Items = new List<MenuItem> { new FeaturedApp { Name = "Game1", Color = "#FF0000", Price = "Free", RowSpan = 2 }, new FeaturedApp { Name = "Game2", Color = "#00FF00", Price = "$2.99" }, new FeaturedApp { Name = "Game3", Color = "#0000FF", Price = "Free" }, new NavigationItem { Name = "Free Games" }, new NavigationItem { Name = "Paid Games" }, } } }; } }

class MenuGroup { public string Title { get; set; } public List<MenuItem> Items { get; set; } }

<common:LayoutAwarePage x:Name="pageRoot" x:Class="PanoramaDemo.Views.MainPage" DataContext="{StaticResource MainViewModel1}" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:PanoramaDemo.Views" xmlns:common="using:PanoramaDemo.Common" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Page.Resources> <!-- Collection of grouped items displayed by this page, bound to a subset of the complete item list because items in groups cannot be virtualized --> <CollectionViewSource x:Name="groupedItemsViewSource" Source="{Binding Groups}" IsSourceGrouped="true" ItemsPath="Items" /> </Page.Resources>

<GridView Grid.RowSpan="2" ItemsSource="{Binding Source={StaticResource groupedItemsViewSource}}" ItemTemplateSelector="{StaticResource MenuItemDataTemplateSelector1}" SelectionMode="None" Padding="116,137,40,46"> <GridView.ItemContainerStyle>...</GridView.ItemContainerStyle> <GridView.ItemsPanel> <ItemsPanelTemplate> <VirtualizingStackPanel Orientation="Horizontal" /> </ItemsPanelTemplate> </GridView.ItemsPanel> <GridView.GroupStyle> <GroupStyle> <GroupStyle.HeaderTemplate> <DataTemplate> <Grid Margin="1,0,0,6"> <TextBlock Text="{Binding Title}" Margin="3,-7,10,10" Style="{StaticResource GroupHeaderTextStyle}" /> </Grid> </DataTemplate> </GroupStyle.HeaderTemplate> <GroupStyle.Panel> <ItemsPanelTemplate> <VariableSizedWrapGrid Orientation="Vertical" Margin="0,0,80,0" ItemWidth="300" ItemHeight="200" /> </ItemsPanelTemplate> </GroupStyle.Panel> </GroupStyle> </GridView.GroupStyle> </GridView>

GridView •Tiles

•Different

Content

•Different

Sizes

•Grouping

•Semantic

Zoom

<SemanticZoom x:Name="semanticZoom" Grid.RowSpan="2"> <SemanticZoom.ZoomedOutView> <GridView x:Name="GridZoomOut" SelectionMode="None" ScrollViewer.IsHorizontalScrollChainingEnabled="False" Padding="116,137,40,46" IsSwipeEnabled="True" Foreground="White"> <GridView.ItemTemplate> <DataTemplate> <Grid Background="White" Width="200" Height="200"> <TextBlock Foreground="Black" HorizontalAlignment="Left" VerticalAlignment="Bottom" Text="{Binding Group.Title}" Margin="10" FontFamily="Segoe UI Light" FontSize="36" /> </Grid> </DataTemplate> </GridView.ItemTemplate> <GridView.ItemsPanel> <ItemsPanelTemplate> <WrapGrid MaximumRowsOrColumns="5" VerticalChildrenAlignment="Top" /> </ItemsPanelTemplate> </GridView.ItemsPanel> </GridView> </SemanticZoom.ZoomedOutView> <SemanticZoom.ZoomedInView> <GridView ItemsSource="{Binding Source={StaticResource groupedItemsViewSource}}“ ...

public MainPage() { this.InitializeComponent(); (semanticZoom.ZoomedOutView as GridView).ItemsSource = groupedItemsViewSource.View.CollectionGroups; }

Recap & Questions

top related