Upload
sherman-ford
View
224
Download
1
Embed Size (px)
Citation preview
Charles Petzoldwww.charlespetzold.com
Controls and Data Binding
Agenda
• Built-in controls• Styles and templates• Data binding• Model-View-ViewModel (MVVM)• Items controls• The WebBrowser control• Application bars• Toolkit controls
• SWP contains assortment of basic controls– TextBox and PasswordBox– Button, CheckBox, RadioButton, and
HyperlinkButton– Slider and ProgressBar– MediaElement and MultiScaleImage– ListBox, Pivot, and Panorama– WebBrowser and other controls
• Touch support built in• More in Silverlight for Windows Phone
Toolkit
Controls
Button Control
<Button Width="400" Height="240" FontSize="{StaticResource PhoneFontSizeExtraLarge}" Content="Click Me" Click="OnClick" />
private void OnClick(object sender, RoutedEventArgs e){ ...}
Button with Custom Content
<Button Width="400" Height="240" Click="OnClick"> <Button.Background> <LinearGradientBrush StartPoint="0.5,0.0" EndPoint="0.5,1.0"> <GradientStop Offset="0.0" Color="#FF808080" /> <GradientStop Offset="1.0" Color="#FF202020" /> </LinearGradientBrush> </Button.Background> <Button.Content> <!-- Insert penguin XAML here --> </Button.Content></Button>
TextBox Control
// XAML<TextBox x:Name="Input" FontSize="36" />
// C#string input = Input.Text; // What the user typed
• SIP = Software Input Panel• InputScope property of text-input elements
permits SIP to be tailored to input type• More than 60 input scopes available
SIPs and Input Scopes
InputScope="Default"
InputScope="TelephoneNumber"
Specifying an Input Scope
// Short form (XAML)<TextBox x:Name="Input" InputScope="TelephoneNumber" />
// Long form (XAML with IntelliSense)<TextBox x:Name="Input"> <TextBox.InputScope> <InputScope> <InputScopeName NameValue="TelephoneNumber" /> </InputScope> </TextBox.InputScope></TextBox>
// C#Input.InputScope = new InputScope() { Names = { new InputScopeName() { NameValue = "TelephoneNumber" } } };
Useful Input Scopes
Name Description
Default Basic text entry (letters, numbers, and symbols)
Text Text entry with auto-capitalization, auto-complete, and more
Number Numeric data entry
TelephoneNumber Phone number data entry
EmailSmtpAddress E-mail address data entry
Url URL data entry
ProgressBar Control
<!-- ProgressBar with default min and max (0 and 100) --><ProgressBar Value="40" />
<!-- ProgressBar with custom min and max --><ProgressBar Minimum="1" Maximum="1000" />
<!-- Indeterminant ProgressBar --><ProgressBar IsIndeterminant="true" />
ProgressBar showing 40% complete Indeterminant ProgressBar
ProgressBar Performance
// Never do this!<ProgressBar x:Name="Progress" IsIndeterminant="true" />
// Do this instead<ProgressBar x:Name="Progress" /> ...Progress.IsIndeterminant = true; // Operation begins ...Progress.IsIndeterminant = false; // Operation completes
demoControl Basics
• Allow look and feel to be factored from content– Provide level of indirection between visual
properties and their values• Style = Collection of property values
– Define style as XAML resource– Apply style using {StaticResource} markup
extension– Or apply it programmatically
• Global scope or local scope
Styles
Defining a Global Style
// App.xaml<Application.Resources> <Style x:Key="ButtonStyle" TargetType="Button"> <Setter Property="Width" Value="400" /> <Setter Property="Height" Value="240" /> </Style></Application.Resources>
Defining a Local Style
// MainPage.xaml<Grid.Resources> <Style x:Key="ButtonStyle" TargetType="Button"> <Setter Property="Width" Value="400" /> <Setter Property="Height" Value="240" /> </Style></Grid.Resources>
Applying Styles
<Button Style="{StaticResource ButtonStyle}" ... /><Button Style="{StaticResource ButtonStyle}" ... /><Button Style="{StaticResource ButtonStyle}" ... /><Button Style="{StaticResource ButtonStyle}" Width="100" ... />
Explicit property value overrides style property value
<Style x:Key="ButtonStyle" TargetType="Button"> <Setter Property="Width" Value="400" /> <Setter Property="Height" Value="240" /></Style>
<Style x:Key="TranslucentButtonStyle" TargetType="Button" BasedOn="{StaticResource ButtonStyle}"> <Setter Property="Opacity" Value="0.5" /></Style>
BasedOn Styles
demoStyles
• Redefine a control’s entire visual tree– Perform deep customization while retaining
basic behavior of control– Exposed through control's Template property
• Inherited from Control base class• Use {TemplateBinding} to flow property
values from control to template• Use ContentPresenter and ItemsPresenter to
flow content and items to template
Control Templates
Elliptical Button
<Button Foreground="Black"> <Button.Template> <ControlTemplate TargetType="Button"> <Grid> <Ellipse Width="256" Height="128"> <Ellipse.Fill> <RadialGradientBrush GradientOrigin="0.25,0.25"> <GradientStop Offset="0.25" Color="White" /> <GradientStop Offset="1.0" Color="Red" /> </RadialGradientBrush> </Ellipse.Fill> </Ellipse> <TextBlock FontSize="24" Text="Click Me" HorizontalAlignment="Center" VerticalAlignment="Center" /> </Grid> </ControlTemplate> </Button.Template></Button>
<Button Width="256" Height="128" FontSize="24" Content="Click Me" Foreground="Black"> <Button.Template> <ControlTemplate TargetType="Button"> <Grid> <Ellipse Width="{TemplateBinding Width}" Height="{TemplateBinding Height}"> <Ellipse.Fill> <RadialGradientBrush GradientOrigin="0.25,0.25"> <GradientStop Offset="0.25" Color="White" /> <GradientStop Offset="1.0" Color="Red" /> </RadialGradientBrush> </Ellipse.Fill> </Ellipse> <TextBlock FontSize="24" Text="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center" /> </Grid> </ControlTemplate> </Button.Template></Button>
{TemplateBinding}
<Button Width="256" Height="128" FontSize="24" Content="Click Me" Foreground="Black"> <Button.Template> <ControlTemplate TargetType="Button"> <Grid> <Ellipse Width="{TemplateBinding Width}" Height="{TemplateBinding Height}"> <Ellipse.Fill> <RadialGradientBrush GradientOrigin="0.25,0.25"> <GradientStop Offset="0.25" Color="White" /> <GradientStop Offset="1.0" Color="Red" /> </RadialGradientBrush> </Ellipse.Fill> </Ellipse> <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" /> </Grid> </ControlTemplate> </Button.Template></Button>
ContentPresenter
Combining Styles and Templates
<Style x:Key="EllipticalButton" TargetType="Button"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="Button"> <Grid> <Ellipse Width="{TemplateBinding Width}" Height="{TemplateBinding Height}"> <Ellipse.Fill> <RadialGradientBrush GradientOrigin="0.25,0.25"> <GradientStop Offset="0.25" Color="White" /> <GradientStop Offset="1.0" Color="Red" /> </RadialGradientBrush> </Ellipse.Fill> </Ellipse> <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" /> </Grid> </ControlTemplate> </Setter.Value> </Setter></Style>
demoControl Templates
• Permits properties of one object to be bound to properties of another– Target property must be DependencyProperty– Source property can be any type of property– Source can be a collection if target is items
control• OneTime, OneWay, and TwoWay bindings• {Binding} markup extension provides
declarative support for data binding
Data Binding
Data Binding Schema
ValueConverter
Target
DependencyProperty
BindingObject
Source
Property
Converts data format and optionally validates it in two-way data binding scenarios
Provides data and optionally receives it (two-way binding)
Consumes data and optionally sends it (two-way binding)
Flows data between source and target
• Creates Binding objects declaratively
{Binding}
<TextBox x:Name="Input" FontSize="36" /><TextBlock x:Name="Output" Text="{Binding Text}" FontSize="36" />
TextBlock
TextProperty
BindingObject
TextBox
TextProperty
Specifying the Data Source (1)// XAML<TextBox x:Name="Input" FontSize="36" /><TextBlock x:Name="Output" Text="{Binding Text}" FontSize="36" />
// C#Output.DataContext = Input;
Specifying the Data Source (2)<TextBox x:Name="Input" Height="24" FontSize="36" /><TextBlock x:Name="Output" FontSize="36" Text="{Binding Text, ElementName=Input}" />
ElementName identifies another XAML element as the data source
Two-Way Data Binding
<TextBox x:Name="Input" Text="40" FontSize="36" /><Slider Minimum="0" Maximum="100" Value="{Binding Text, ElementName=Input, Mode=TwoWay}" />
Mode identifies the binding mode
• Infrastructural interface used in data classes
• Notifies binding object when data changes• Essential for one-way data binding!
INotifyPropertyChanged
Data Class
Property
Property
Property
INotifyPropertyChanged
Implementing INotifyPropertyChangedpublic class Person : INotifyPropertyChanged{ public event PropertyChangedEventHandler PropertyChanged; private decimal _salary; public decimal Salary { get { return _salary; } set { _salary = value; if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Salary")); } }}
• Infrastructural interface used in collection classes
• Notifies binding object when collection changes
INotifyCollectionChanged
Collection Class
Item
Item
Item
INotifyCollectionChanged
IList
ICollection
IEnumerable
• BCL collection class that implements INotifyCollectionChanged– System.Collections.ObjectModel namespace
• Fires CollectionChanged events when items are added or removed (or collection is refreshed)
ObservableCollection
// Ordinary collectionList<string> names = new List<string>();
// Observable collectionObservableCollection<string> names = new ObservableCollection<string>();
• Objects that convert values involved in data binding from one type to another
• Implement IValueConverter– Convert – Convert from type A to type B– ConvertBack – Convert from type B to type A
• Specified with Converter attribute in {Binding} expression
Value Converters
ImageConverter
public class ImageConverter : IValueConverter{ public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { BitmapImage bi = new BitmapImage(); bi.SetSource(new MemoryStream((Byte[])value)); return bi; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); }}
Using ImageConverter
<Grid.Resources> <local:ImageConverter x:Key="ImageConverter" /></Grid.Resources> . . .<DataTemplate> <Image Source="{Binding ThumbnailImage, Converter={StaticResource ImageConverter}}" /></DataTemplate>
demoData Binding
• Controls that display collections of items• Generally acquire items through data
binding• Data templates control how items are
rendered
Items Controls
PivotListBox Panorama
ListBox Control
// XAML<ListBox FontSize="{StaticResource PhoneFontSizeExtraLarge}" SelectionChanged="OnSelectionChanged"> <ListBoxItem Content="Item One" /> <ListBoxItem Content="Item Two" /> <ListBoxItem Content="Item Three" /></ListBox>
// C#private void OnSelectionChanged(object sender, SelectionChangedEventArgs e){ int index = (sender as ListBox).SelectedIndex; ...}
ListBox with Rich Content
<ListBox> <StackPanel Orientation="Horizontal"> <Image Source="Item.png" Margin="8" /> <StackPanel Orientation="Vertical"> <TextBlock Text="Item One" Style="{StaticResource PhoneTextExtraLargeStyle}" /> <TextBlock Text="Convallis dapibus non ut justo" Style="{StaticResource PhoneTextAccentStyle}" /> </StackPanel> </StackPanel> . . .</ListBox>
ListBox Data Binding
// XAML<ListBox x:Name="List" FontSize="{StaticResource PhoneFontSizeExtraLarge}" />
// C#string[] items = { "Item One", "Item Two", "Item Three"};
List.ItemsSource = items;
ListBox Data Templates
<ListBox x:Name="List"> <ListBox.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <Image Source="{Binding Source}" Margin="8" /> <StackPanel Orientation="Vertical"> <TextBlock Text="{Binding Title}" Style="..." /> <TextBlock Text="{Binding Description}" Style="..." /> </StackPanel> </StackPanel> </DataTemplate> </ListBox.ItemTemplate></ListBox>
Providing a Data Source
ObservableCollection<Item> items = new ObservableCollection<Item>();items.Add(new Item { Source = "Item.png", Title = "Item One", Description = "Convallis dapibus non ut justo" });items.Add(new Item { Source = "Item.png", Title = "Item Two", Description = "Convallis dapibus non ut justo" });items.Add(new Item { Source = "Item.png", Title = "Item Three", Description = "Convallis dapibus non ut justo" });List.ItemsSource = items;
public class Item{ public string Source { get; set; } public string Title { get; set; } public string Description { get; set; }}
• SelectedIndex gets and sets index of selected item– -1 means no item is currently selected
• SelectedItem property gets reference to item that is currently selected – with strong typing– null means no item is currently selected
The SelectedItem Property
// SelectedItem returns an Item reference because ListBox// is bound to collection of Item objectsItem item = List.SelectedItem as Item;String title = item.Title; // e.g., "Item One"
• Model-View-ViewModel• Popular design pattern used by teams doing
WPF, Silverlight, and phone development– Loose coupling; separation of concerns– Enhanced testability and "Blendability"– Based on Martin Fowler's Presentation Model
pattern• Devised in 2005 by Microsoft's John
Gossman• WP7 lacks rich MVVM support
(commanding)
MVVM
Model-View-ViewModel
Model ViewModel View
Control
ControlProperty
PropertyModelClass
ModelClass
ModelClass
Data
Bin
din
g
ViewModel Example
public class ViewModel{ public ObservableCollection<Item> Items { get; set; }
public ViewModel() { Items = new ObservableCollection<Item>(); Items.Add(new Item { Source = "Item.png", Title = "Item One", Description = "..." }); Items.Add(new Item { Source = "Item.png", Title = "Item Two", Description = "..." }); Items.Add(new Item { Source = "Item.png", Title = "Item Three", Description = "..." }); }}
Binding to a ViewModel
<Grid ...> <Grid.Resources> <local:ViewModel x:Key="ItemsViewModel" /> </Grid.Resources> <ListBox x:Name="List" ItemsSource="{Binding Items}" DataContext="{StaticResource ItemsViewModel}"> <ListBox.ItemTemplate> <DataTemplate> ... </DataTemplate> </ListBox.ItemTemplate> </ListBox></Grid>
demoListBoxes, Data Binding, and MVVM
Pivot Control
• Functionally similar to Tab control• Divides a page into navigable items
(PivotItems)• Implemented in Microsoft.Phone.Controls.dll
Declaring a Pivot Control
<controls:Pivot x:Name="PivotControl" Title="GEEK FEED"> <controls:PivotItem Header="abc"> <!-- Declare PivotItem content here --> </controls:PivotItem> <controls:PivotItem Header="bbc"> <!-- Declare PivotItem content here --> </controls:PivotItem> <controls:PivotItem Header="wired"> <!-- Declare PivotItem content here --> </controls:PivotItem></controls:Pivot>
• Gets and sets index of current PivotItem• Can't be set until control fires Loaded event
if control contains more than three PivotItems
The SelectedIndex Property
// Get SelectedIndex (works anywhere)int index = PivotControl.SelectedIndex;
// Set SelectedIndex (works reliably only after Loaded event)PivotControl.SelectedIndex = 3;
demoPivot Control
Panorama Control
• Divides page into navigable PanoramaItems• Supports image background for magazine
feel• Implemented in Microsoft.Phone.Controls.dll
Declaring a Panorama Control
<controls:Panorama x:Name="PanoramaControl" Title="pictures"> <controls:Panorama.Background> <ImageBrush ImageSource="PanoramaBackground.png"/> </controls:Panorama.Background> <controls:PanoramaItem Header="gallery"> <!-- Declare PanoramaItem content here --> </controls:PanoramaItem> <controls:PanoramaItem Header="recent"> <!-- Declare PanoramaItem content here --> </controls:PanoramaItem> <controls:PanoramaItem Header="samples"> <!-- Declare PanoramaItem content here --> </controls:PanoramaItem></controls:Panorama>
• Panorama's SelectedIndex property is read-only
• Set SelectedIndex indirectly by setting DefaultItem
The DefaultItem Property
// Get SelectedIndexint index = PanoramaControl.SelectedIndex;
// Force SelectedIndex by setting DefaultItemPanoramaControl.DefaultItem = PanoramaControl.Items[3];
demoPanorama Control
• Displays live HTML content from URI or string– Source property downloads content– NavigateToString method injects content– IsScriptEnabled property controls script support
• Defaults to false; set to true to enable script• InvokeScript method and ScriptNotify event
facilitate communication between app and script
• Supports isolated storage as source of content– With support for relative URIs
WebBrowser Control
Displaying Remote Content
<phone:WebBrowser Source="http://www.bing.com" IsScriptEnabled="true" />
Inserting Content
// XAML<phone:WebBrowser x:Name="Browser" Loaded="OnWebBrowserLoaded" />
// C#private void OnWebBrowserLoaded(object sender, RoutedEventArgs e){ Browser.NavigateToString("<h1>Hello, phone</h1>");}
• Add pages to project– Set build action to Content– URIs inside must be absolute
• Load pages with XNA's TitleContainer.OpenStream– Microsoft.Xna.Framework
assembly• Read content with
StreamReader• Pass content to WebBrowser
control with NavigateToString
Loading Local Pages
local.html
<html><body style="background: black"><img src="http://www.wintellect.com/images/WintellectLogo.png" /></body></html>
URI must be absolute since origin is undefined
Loading local.html
// XAML<phone:WebBrowser x:Name="Browser" Loaded="OnWebBrowserLoaded" />
// C#private void OnWebBrowserLoaded(object sender, RoutedEventArgs e){ StreamReader reader = new StreamReader(TitleContainer.OpenStream("local.html")); Browser.NavigateToString(reader.ReadToEnd());}
• For local pages with relative links, store pages and resources they reference in isolated storage– Store entire sites on the phone– One usage scenario: HTML-based help systems
• Optionally use WebBrowser.Base property to specify base folder for relative links
• App must write pages to isolated storage– No tooling to help out
WebBrowser and Isolated Storage
Isolated Storage
Using Isolated Storage
<phone:WebBrowser Base="Help" Source="Page1.html" />
HelpMain
Page1.html
Page2.html
Styles.css
Pages can contain relative links to each other and to other resources
Application
Relative URI refers to resource in isolated storage
• Invokes script functions in WebBrowser control– Don't forget IsScriptEnabled="true"
• Calls are synchronous
WebBrowser.InvokeScript
// C#string result = Browser.InvokeScript("toUpper", "Hello, phone").ToString();
// JavaScriptfunction toUpper(text) { return text.toUpperCase(); // Returns "HELLO, PHONE"}
• Event fired by WebBrowser control when script inside it calls window.external.notify
WebBrowser.ScriptNotify
// JavaScriptwindow.external.notify('Ready');
// C#private void OnScriptNotify(object sender, NotifyEventArgs e){ MessageBox.Show(e.Value); // e.Value == "Ready"}
demoWebBrowser Control
Application Bars
• Quick, easy access to common tasks– Up to four buttons with hints/labels– Up to five menu items
• "Use icon buttons for the primary, most-used actions in the application. Do not use four icons just to use them. Less is more in this space."
Declaring an Application Bar
<phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar IsVisible="True"> <shell:ApplicationBarIconButton IconUri="/Icons/appbar.refresh.rest.png" Text="Refresh" Click="OnRefreshButtonClicked" /> <shell:ApplicationBarIconButton IconUri="/Icons/appbar.settings.rest.png" Text="Settings" Click="OnSettingsButtonClicked" /> </shell:ApplicationBar></phone:PhoneApplicationPage.ApplicationBar>
Processing Button Clicks
void OnRefreshButtonClicked(object sender, EventArgs e){ // TODO: Respond to Refresh button}
void OnSettingsButtonClicked(object sender, EventArgs e){ // TODO: Respond to Settings button}
Disabling Buttons in Code
// XAML<shell:ApplicationBarIconButton x:Name="RefreshButton" IconUri="/Icons/appbar.refresh.rest.png" Text="Refresh" Click="OnRefreshButtonClicked" />
// This throws a NullReferenceExceptionRefreshButton.IsEnabled = false;
// This doesn't(ApplicationBar.Buttons[0] as ApplicationBarIconButton).IsEnabled = false;
Application Bar Icons
• 32 stock icons provided in WP7 SDK– \Program Files\Microsoft SDKs\Windows Phone\
v7.0\Icons\dark• Use "dark" icons only in application bars• Set Build Action to "Content" in Visual
Studio
Refresh New Delete Save
Play Pause Settings Download
Custom Application Bar Icons
• Icon must be 48 x 48 pixels• Icon must have a transparent background• Icon foreground must be white
– Allows OS to colorize based on selected theme• http://www.kirupa.com/windowsphone/
creating_custom_applicationbar_icon.htm
demoApplication Bars
• Silverlight for Windows Phone Toolkit contains additional controls– Source code– Binaries– Samples
• http://silverlight.codeplex.-com/releases/view/55034
Toolkit Controls
Using the ToggleSwitch Control// XAML<toolkit:ToggleSwitch Header="Wi Fi networking" Click="OnClick" />
// C#private void OnClick(object sender, RoutedEventArgs e){ if ((bool)(sender as ToggleSwitch).IsChecked) MessageBox.Show("On"); else MessageBox.Show("Off");}
Using the DatePicker Control
// XAML<toolkit:DatePicker ValueChanged="OnValueChanged" />
// C#private void OnValueChanged(object sender, DateTimeValueChangedEventArgs e){ MessageBox.Show(e.NewDateTime.ToString());}
You provide these icons; DatePicker provides the application bar and buttons
Charles Petzoldwww.charlespetzold.com
Questions?