WPF & Silverlight
Download
Report
Transcript WPF & Silverlight
Creating rich applications
using
Model View ViewModel
David Ross
http://www.pebblesteps.com
Presentation Highlights
Introduction to WPF/Silverlight
Event based development
Data binding
Templates
Presentation Patterns
Testing
Useful frameworks and Tools
WPF
Fast GUI framework that uses the DirectX games
engine for rendering
Part of Windows Vista but back ported to XP (features
such as transparency, shadows, pixel shaders etc work
poorly on that platform)
Mature technology – Now version 3 (3.0, 3.5, 4.0)
WPF cycle linked to Visual Studio releases/Service
Packs
Silverlight
Browser plugin - Yearly release cycle (V5 in beta)
Originally a cut down version of WPF but due to
release cycle often gets features before WPF
Development platform for Windows Phone 7
Out of Browser mode makes it look like a WPF
App/can run outside of the sandbox
All communication with the server is via asynchronous
methods – Blocking operations would crash the
browser
Comparison to Windows Forms
WinForms follow the underlying Windows GDI model
Every item on the screen that can accept a mouse action is a
Window i.e. One screen might have 100 Windows
Controls are responsible for their rendering
Not extensible
WPF/Silverlight is a complete rewrite and bypasses GDI
One screen for the entire App
All visual elements can accept mouse clicks – Everything is a
Button
Rendering/Visualisation of ANY control is overrideable
All controls can have other controls embedded inside them –
Everything is a Panel
Data Binding works!
Development
XAML – Extensible Application Markup Language
XML based programming language
Used to create a tree of objects (must have parameter
free constructors)
Used to describe the Scene Graph in WPF and the
Workflow steps in Windows Workflow Foundation
Code behind in any .NET language (C#, VB.NET, F#
etc)
Dependency Properties
A Control may have hundreds of properties (Font,
Height, Width, Transparency etc)
To save memory Controls of the same type SHARE the
same memory for properties (Flyweight pattern )
When you set a Property (XAML, programmatically)
you override the shared default value
Attached Properties
DependencyProperties include runtime magic to
override defaults
Extended to allow Properties to be added/removed
from a Control at run time
A control sitting inside a Grid is given attached
properties for the Column and Row it should sit within
<Rectangle Grid.Row="1" Grid.RowSpan="6" Fill="#73B2F5"/>
Hence Parent can iterate over child controls and check
if they have used an Attached Property to override the
defaults
Layout Panels
Grid Panel
Items are placed into columns and rows
Items can span across columns and rows
Stack Panel
Appends items either horizontally and vertically after one
another
Good for displaying items of different sizes
Canvas – Used for (X, Y) positioning i.e. games or graphs
Wrap Panel – Items are placed after each other and then
wraps
Dock Panel – Winform like docking
Building pages with Events
Windows Form and classic ASP.NET development style
Events bubble up until they either are discarded or are used
<Window
x:Class="EventBasedDevelopment.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">
<StackPanel>
<TextBlock Name="Result" Text="Hello World"/>
<Button Click="ButtonAClick">Click me</Button>
<StackPanel Button.Click ="ButtonBClick">
<Button>Click me</Button>
</StackPanel>
</StackPanel>
</Window>
Code behind
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void ButtonAClick(object sender, RoutedEventArgs e)
{
Result.Text = "Clicked by button A";
}
private void ButtonBClick(object sender, RoutedEventArgs e)
{
Result.Text = "Clicked by button B";
}
}
Result
Data Binding
Instead of manually changing the text after a mouse click WPF can
do it automatically
Almost everything can be data bound from setting the Text on a
control, to its height, visibility, font, colour etc
Types
One Time – Value is read off the object once when the Control is
first created
One Way – Value is read off the object each time it changes
Two Way – Value that has been changed on the GUI is pushed to
the object
One Way To Source – GUI can change object, but object can’t
change GUI
Only works with Properties public fields can’t be bound to
Data Binding example
<Window
x:Class="SimpleDataBinding.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">
<StackPanel Name="Panel">
<TextBlock Text="{Binding Path=Color}" Background="{Binding
Path=ColorBrush}"/>
<Button Click="Green_Click">Make Green</Button>
<Button Click="Blue_Click">Make Blue</Button>
<Button Click="Red_Click">Make Red</Button>
</StackPanel>
</Window>
public partial class MainWindow : Window
{
public MainWindow()
{
Color = Colors.Purple;
DataContext = this;
InitializeComponent();
}
private void Green_Click(object sender, RoutedEventArgs e)
{
Color = Colors.Green;
}
private void Blue_Click(object sender, RoutedEventArgs e)
{
Color = Colors.Blue;
}
private void Red_Click(object sender, RoutedEventArgs e)
{
Color = Colors.Red;
}
public Color Color { get; set; }
public Brush ColorBrush
{
get { return new SolidColorBrush(Color); }
}
}
Kinda Works
Buttons that are
clicked don’t update
the Textbox
WPF uses the
Observer pattern
We didn’t notify
WPF that the
properties had been
modified
INotifyPropertyChanged
public partial class MainWindow : Window, INotifyPropertyChanged
{
public MainWindow()
{
...
public event PropertyChangedEventHandler PropertyChanged;
private Color _color;
public Color Color
{
get { return _color; }
set
{
_color = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("Color"));
PropertyChanged(this, new PropertyChangedEventArgs("ColorBrush"));
}
}
}
}
INotifyPropertyChanged
For WPF Data Binding to work in a OneWay or
TwoWay scenario any changes to an object are
announced with an event
Instead of using List<T> use an
ObservableCollection<T> announces when items are
added or removed from the collection
You need to fire an event for each property that has
become dirty after an action i.e. A First Name change
will also dirty Full Name
Replace string with Expression
PropertyChanged(this, new
PropertyChangedEventArgs("Color"));
If I rename Color to Colour and don’t update the string
the controls wont be notified/updated
Common pattern is to use an Expression tree and a
shared base class for data objects
RaisePropertyChanged(() => Color);
The Expression is then converted into a string
Removing the plumbing with AOP
Aspect Orientated Programming is used to remove
duplicate code that “crosses concerns” i.e. Security,
Logging, PropertyChangedEvents
Available in Inversion of Controls Containers (Castle,
Spring.NET, Ninject, Unity etc) and Assembly rewriters
(PostSharp)
Use an Interceptor to grab the call to object.Property = X
and replace with:
object.Property = X
PropertyChanged(this, “Property”)
Code can then be “simplified” back to a C# Auto property
ICommand – Smarter events
We also use Data Binding for calling methods
Properties
CanExecute – Returns a Boolean to indicate whether a
method can be called
Execute – Delegate that is executed by WPF when the action
occurs
CanExecuteChanged – Used to tell WPF that the command
is or isn’t available
Hence we can turn functionally on and off easily
Events can be moved out of the code behind and into the
Data Bound object which is probably modified by the
action anyway
IValueConverter
The types exposed in our Data Bound object may not
be viewable
A true/false flag may mean different panels are visible
on an entry screen
A negative number may indicate the account is in
overdraft and it should be Red
Boolean to Visibility Converter
public class BooleanToVisibilityValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo
culture)
{
if (!(value is bool))
return null;
if ((bool)value)
return Visibility.Visible;
return Visibility.Hidden;
}
public object ConvertBack(object value, Type targetType, object parameter,
CultureInfo culture)
{
throw new NotImplementedException();
}
}
<Window x:Class="SimpleBooleanConverter.MainWindow“
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:System="clrnamespace:System;assembly=mscorlib" xmlns:SimpleDataBinding="clrnamespace:SimpleDataBinding" Title="MainWindow" Height="350" Width="525">
Make the converter
available
<Window.Resources>
<SimpleDataBinding:BooleanToVisibilityValueConverter x:Key="blnToVis"/>
<System:Boolean x:Key="PlaysCricket">False</System:Boolean>
<Style TargetType="TextBlock">
<Setter Property="Width" Value="150"/>
</Style>
</Window.Resources>
XAML as a factory
<StackPanel>
<StackPanel Orientation="Horizontal" VerticalAlignment="Top">
Bool in the XAML
<TextBlock>How old are your?</TextBlock>
scope is passed to the
<TextBox Name="Age"/>
converter
</StackPanel>
<StackPanel Visibility="{Binding Source={StaticResource PlaysCricket},
Converter={StaticResource blnToVis}}">
<StackPanel Orientation="Horizontal" VerticalAlignment="Top">
<TextBlock>Are you a bowler?</TextBlock>
<ComboBox>
<ComboBoxItem>No</ComboBoxItem>
<ComboBoxItem>Fast</ComboBoxItem>
<ComboBoxItem>Spin</ComboBoxItem>
</ComboBox>
</StackPanel>
<StackPanel Orientation="Horizontal" VerticalAlignment="Top">
<TextBlock>Are you a batsman?</TextBlock>
<ComboBox>
<ComboBoxItem>No</ComboBoxItem>
<ComboBoxItem>Yes</ComboBoxItem>
</ComboBox>
</StackPanel>
</StackPanel>
</StackPanel>
Data Templates
We have a list<Animal> or
ObservableCollection<Animal> is the collection
elements can change
The list includes instances of Cat, Dog, Horse wouldn’t
it be nice if we could display different sets of controls
for each of the different types of Animal as each has
different attributes
<Window
x:Class="DataTemplateAnimals.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:DataTemplateAnimals="clr-namespace:DataTemplateAnimals"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<DataTemplate DataType="{x:Type DataTemplateAnimals:Cat}">
<WrapPanel>
<TextBlock>I am a happy kitty.</TextBlock>
<TextBlock>Lives left:</TextBlock>
<TextBlock Text="{Binding Path=LivesLeft}"/>
</WrapPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type DataTemplateAnimals:Dog}">
<WrapPanel>
<TextBlock>I am a doggy.</TextBlock>
<TextBlock>I bark this much:</TextBlock>
<TextBlock Text="{Binding Path=BarkVolume}"/>
</WrapPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<ListBox ItemsSource="{Binding Path=Animals}"></ListBox>
</Grid>
</Window>
public partial class MainWindow : Window
{
public ObservableCollection<Animal> Animals { get; set; }
public MainWindow()
{
Animals = new ObservableCollection<Animal>
{
new Dog {Age = 5, AgeInAnimalYears = 30, BarkVolume = 3},
new Cat {Age = 5, AgeInAnimalYears = 30, LivesLeft = 7}
};
DataContext = this;
InitializeComponent();
}
}
ControlTemplate
Allows you to change the visual tree of a Control
Thus allows everything to be changed
How it looks
How it deals with events
IDataErrorInfo
In the data binding setup turn on validation
User edits still populates the bound object
Only allow a Save operation was the validation succeeds
class Example : IDataErrorInfo
{
public int Age {get; set;}
public string Error {get; private set;}
public string this[string name]
{
get {
if(name = “Age”){
if(Age>120 || Age < 18) return “Must be over 18”;
}
return null;
}
}
Triggers
WPF only
A change to a property on a bound object can automatically
trigger a visual change such as using a different Style
<Style TargetType="{x:Type Button}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="BitmapEffect">
<Setter.Value>
<OuterGlowBitmapEffect GlowColor="Gold" GlowSize="10" />
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
Storyboard
Time line of changes that are made to an object that
can be programmatically kicked off
Button fades in and out after a mouse over
Labels become textboxes when moving into edit mode
Animation are easy
set the frame rate
set the start and end position
set the duration for the move
Visual State Manager
Silverlight 2.0 and then ported to WPF 4.0
Control is a state machine
Each state can have a different visual look – i.e. Button is
enabled, disabled, has focus, clicked etc
Storyboard used to define the look of a state and how
you move between the states
Microsoft Blend is the best tool to create Storyboards
and to define different visual states for the controls
User Controls
Used in 99% of cases
Inherits from UserControl
Define the look and feel/capability of the control by
adding Child Elements to it
Can use custom DependencyProperties to customise
behaviour but typically use Data Binding instead
No ability to change the layout
Custom Controls
Inherits from Control
Custom DependencyProperties used so that the
control’s behaviour can be modified in the properties
window
Define a ControlTemplate for layout and to include
child controls
Used for creating Calendar controls etc where the end
user may want to customise the layout or rendering
Presentation Patterns
Used to separate the concerns of showing the data,
editing the data and processing the user’s interactions
Model View Controllers i.e. ASP.NET MVC, MFC,
Struts, JSF
Model View Presenter i.e. Winform CAB, ASP.NET
MVP
Model View ViewModel i.e WPF & Silverlight best
practice
What is the Model?
Its all the information that the user is interacting with
Usually reaches user after going through a service on a
server
It should mirror (model) the problem domain
Often hierarchal
Often needs to be consistent i.e. Saving a model that is
partially populated will fail
What is the View?
The “stuff” that is visible to the user
Responsible for presentation only
Displays the model but data editing/transforming is
delegated to another component
MVC
Controller handles the HTTP request, populates a model
and determines which View to display the results
Repeat…
*
View
1
Controller
Model
MVP
In ASP.NET MVC a view is (re)created each request
In MVP the View sticks around i.e thick client or
session/view state
Event based
Presenter listens to changes on the View
View accesses Model data via Presenter
View
1
1
Presenter
Model
MVVM
MVP but with the benefits of using Data Binding
hence ViewModel doesn’t need to listen to events from
the View
ViewModel doesn’t “know” about the View so we can
easily unit test presentation logic (by faking out the
view)
View
*
1
ViewModel
Model
What is the ViewModel
Wraps the Model
Collapses complex object graph into a flat structure
Simplifies the view by Aggregating and Retrieving i.e. Instead
of transversing through a tree the ViewModel does it
Implements interface INotifyPropertyChanged
Informs the View to redraw/update itself
ViewModel can have other ViewModels as properties
Each region on the screen can be a ViewModel
Detail views etc
Can be inconsistent domain wise i.e. ViewModel can be
populated with incomplete or badly formed data. Once
correct populate the Model
ViewModel versus Converter
A ViewModel may be displayed by many Views
Hence it an be frowned upon having properties that
expose Visual elements
Brushes, Visibility, Animation Storyboards etc
Converters can act as bridge between the View and the
ViewModel
Note: This rule/pattern is REGULARLY broken i.e. expose
a Brush if you have only one View and refactor to
converter when required
Data Templates and ViewModels
Where the magic happens
Data Template is a View factory that uses an Object Type as
the Key
Parent ViewModel exposes other ViewModels as properties
and DataTemplate automatically finds the View to display
A PageViewModel may have properties for different visual
regions
A region can be changed just by replacing a property with a
different ViewModel
Implies 90% of the time there is a single View per
ViewModel
DataTemplate - Wizards
User is presented with a chain of screens whose contents
depends on the answer of the previous page
Back button must work and if user changes their mind and
causes the navigation direction to change the answers on
the pages must disappear
WizardViewModel manages the screen layout and
navigation
Use a Stack to store User responses that can be popped on
and off as the screen changes
Have a CurrentScreen property/state machine so that the
DataTemplate can automatically choose the correct screen
Testing
ViewModel includes all the “logic” but doesn’t interact with a
View directly – Only notifies
Easy to create a Unit test that changes Properties etc and then
verify the results
To check if the Save button is only enabled once all text boxes
are populated
Create ViewModel
Listen for the SaveCommand.CanExecuteChanged event
Assert SaveCommand.CanExecute is false
Populate ViewModel input properties
Assert that SaveCommand.CanExecuteChanged fired
Assert SaveCommand.CanExecute is true
Shared WPF & Silverlight
development
Silverlight is asynchronous only
Cut down version of the .NET framework
Write a single set of C# files that are included in both a
Silverlight and WPF assembly
Patterns and Practices team have written “Project
Linked” that automatically links the files of one project
to another each compile
Use pre-processor exclude WPF only code
#if !SILVERLIGHT
Tools - Snoop
Allows developer to see the Scene Graph of any WPF
application
Almost impossible to debug errors where Control
doesn’t appear correctly out of a DataTemplate without
it
Tools - Blend
Tool used by Designers to create the look and feel for
an application
Built in support for drawing, animations and Visual
State Manager
Blend and Visual Studio share C#, Project and
Solution files hence designers and developers work
together
Design Mode & Blendability
When a ViewModel is constructed it can check if the
application is running inside Visual Studio or Blend
By creating “fake” data and correctly populating all of
the properties the View will then render a fully
working populated screen
Allows Designers to easily style a page
What do frameworks offer
Caliburn.Micro
Convention over Configuration
No data binding elements in XAML instead Data Binding happens at runtime
based on a set of conventions
Button called Authorise will be automatically bound to a command called
AuthoriseCommand
Screen Lifecycle management
Ability to stop application quitting if there is unsaved work
Event Aggregator
Publish-Subscribe infrastructure that allows Views or ViewModels to publish
events and have a completely unrelated component subscribe
Coroutines
Allows developer to build a state machine that will continue at a set execution
point i.e. Once an asynchronous operation has completed restart here. Based
on IResult.
Makes to it easy to create screen flows that don’t share data
What do frameworks offer
Managed Extensibility Framework
Plugin architecture that allows new components (in the form of
binaries) to be added to a solution by placing them into a plugin
folder
In Silverlight allows different application components to be
hosted in different files to make initial application loading faster
Prism
Patterns and Practices for Microsoft
Port of the WinForm framework to WPF
Was created before Model View ViewModel pattern became
prevalent closer to Model View Presenter
Can be overly complex
Questions