WPF
Content
Intro
XAML
Layout
Dependency Properties
Routed Events
Intro
Intro
- Windows Presentation Foundation (WPF)
- Innovative graphical display system
- Built-in hardware acceleration
- Resolution independence
- Targets
- Win Vista, 7 and 8 Desktop Mode
- Metro Toolkit
- Limited to Win 8 only
- Must target .NET 4
Evolution of Windows Graphics
- Before WPF, same display tech for 15 years
- User32
- Traditional look and feel for elements like
- windows, buttons, text boxes, etc.
- GDI/GDI+
- Drawing support
- Render shapes, text and images
- Windows Forms, MFC
- behind the scene User32 and GDI/GDI+ is used
Evolution of Windows Graphics #2
- Different frameworks are just different wrappers
- Performance improvements
- Reduce complexity
- Add prebaked features
- But cannot remove fundamental limitations of User32 and GDI/GDI+
DirectX Graphics Engine
- One way around limitations of User32 and GDI/GDI+
- Mostly toolkit for game programming
- Usually not used for GUI programming
- Low level API
- WPF uses DirectX as underlying graphics technology
- Allows drawing buttons and complex 3D graphics
- And effects and animations etc.
- For certain services User32 is still used
- Input and display management
- Not for drawing
Hardware Acceleration and WPF
- Most modern computers have very powerful graphics cards
- WPF still provides software fallback
- for legacy devices
- but may be much slower
WPF API & Features
- Web-like layout model
- allows flow layout that arranges controls based on content
- Rich drawing model
- Basic shapes, blocks of text and other graphical primitives
- Transparent controls, multiple layers with varying opacities, native 3D support
- Richt text model
- Animations
- Intrinsic part of framework, defined by declarative tags
WPF API & Features #2
- Audio & video support
- Play multiple videos at the same time
- Styles and templates
- Standardize formatting and reuse
- Commands
- Define a single command and reuse it in several places
- Declarative user interface
- Either construct everything in code
- Or set of XML tags (XAML document)
- Separate user interface from code
- Page-based applications
- Browser-like apps
- With forward / backward navigation
Resolution Independence
- Usually developers assume standard monitor resolution
- High resolution monitor - app looks smaller
- E.g. 96 dpi, 120 dpi or retina display
- WPF units
- Measured in device-independent units
XAML
XAML Intro
- Exensible Application Markup Language
- Markup language used to instantiate .NET objects
- Mostly used to construct WPF user interfaces
- XAML defines
- arrangement of panels
- buttons
- controls, etc.
- Tools exist to create XAML
- Visual Studio
- Expression Blend
- Better workflow for designers and developers
XAML Compilation
- XAML solves problem of design collaboration
- XAML is easy and flexible, but also needs to be fast
- XML readable but not compact
- BAML
- Binary Application Markup Language
- Binary representation of XAML
- BAML is embedded as a resource in the final assembly
- BAML is tokenized and optimized (shorter and faster)
- Also possible to use uncompiled XAML
- E.g.: Pulled out of DB as a block of XAML tags
XAML Basics
- Every element in a XAML document maps to an instance of a .NET class
- The name of the element matches the name of the class
- XML allows nesting objects (Containers)
- E.g. Button inside a Grid
- Set properties of a class through attributes
- Not always powerful enough
- Nested tags with special syntax
XAML Basics #2
<Window x:Class="WpfBasics.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">
<Grid>
</Grid>
</Window>
- Blank window
- Top-level window element
- Grid as container
- WPF top-level elements
- Window
- Page (navigable apps)
- Application (define app resources and startup settings)
XAML Attributes
- Window class properties
- Device independent units
- 300x300 pixel on a 96 dpi display
- More pixels on a higher dpi display
Title="MainWindow" Height="350" Width="525"
XAML Namespaces
x:Class="WpfBasics.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- Class name and namespace is needed
- Attribute used to define namespace
- Namespaces may be defined on every element
- But define all namespace on top-level element
- xmlns reserved attribute used to define namespaces
XML Namespaces #2
- http://schemas.microsoft.com/winfx/2006/xaml/presentation
- core WPF namespace
- here declared without namespace prefix
- therefore default namespace for entire document
- http://schemas.microsoft.com/winfx/2006/xaml
- XAML namespace
- Includes XAML utility features, allows you to influence how the document is interpreted
- Mapped to prefix x
- E.g.: <x:ElementName>
Code-Behind Class
// <Window x:Class="WpfBasics.MainWindow"></Window>
namespace WpfBasics {
public partial class MainWindow : Window {
public MainWindow() { InitializeComponent(); }
}
}
- x namespace prefix, places the Class attribute in the XAML namespace
- Class attribute tells the XAML parser to generate a new class with specified name
- That class is derived from the XML element (Window)
- Supply partial class MainWindow, which is merged with the auto generated partial MainWindow class
- Implement event handlers
- InitializeComponent loads BAML and builds the user interface
Naming Elements
<Grid x:Name="MyGrid"></Grid>
// or
<Grid Name="MyGrid"></Grid>
- Naming elements allows referencing controls in code
Type Converters
<TextBox Name="txtQuestion" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
FontFamily="Verdana" FontSize="24" Foreground="Green" ..> </TextBox>
- Attributes of an element set the properties of the corresponding object
- TextBox must provide all properties
- Value of a XML property is always text
- Object properties may hold any type
- XAML parser performs conversion
- Given by type converters
- converts to and from a .NET type
- Here: string to .NET type
Type Converters #2
- XAML parsers finds type converter in two steps
- Examine property declaration, look for TypeConverter attribute
- If no TypeConverter found, check class declaration of data type
- E.g. Forground property uses Brush object
- Brush class uses BrushConverter
- If no TypeConverter is found, XAML parser generates an error
Complex Properties
<Grid x:Name="mainGrid">
<Grid.Background>// ... </Grid.Background>
</Grid>
- Some attributes are objects with own attributes
- It is possible to use a string representation, but error prone and difficult to use
- Property-element syntax
- Parent.PropertyName
- Grid has a Background property that allows to set a brush
- For complex brushes use property-element syntax
- (.) allows to distinguish between nested components and complex properties
Complex Properties #2
<Grid x:Name="mainGrid">
<Grid.Background>
<LinearGradientBrush>
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0.00" Color="Red" />
<GradientStop Offset="0.50" Color="Indigo" />
<GradientStop Offset="1.00" Color="Violet" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Grid.Background>
// ...
</Grid>
- Create nested element to define complex property
- These may also have complex properties
Complex Properties #3
LinearGradientBrush brush = new LinearGradientBrush();
GradientStop gradientStop1 = new GradientStop();
gradientStop1.Offset = 0;
gradientStop1.Color = Colors.Red;
brush.GradientStops.Add(gradientStop1);
GradientStop gradientStop2 = new GradientStop();
gradientStop2.Offset = 0.5;
gradientStop2.Color = Colors.Indigo;
brush.GradientStops.Add(gradientStop2);
GradientStop gradientStop3 = new GradientStop();
gradientStop3.Offset = 1;
gradientStop3.Color = Colors.Violet;
brush.GradientStops.Add(gradientStop3);
mainGrid.Background = brush;
- XAML tags may also be replaced with a set of code statements
Markup Extensions
<Button Foreground="{x:Static SystemColors.ActiveCaptionBrush}">
- XAML property syntax not sufficient for all use cases
- Set a property value to an object that already exists
- Set property value dynamically
- Use markup extensions
- Syntax: {MarkupExtensionClass Argument}
- Here: StaticExtension class (drop Extension by convention)
- All markup extensions derive from System.Windows.Markup.
MarkupExtension. - XAML parser creates instance of StaticExtension passing SystemColors.ActiveCaptionBrush then calls ProvideValue()
Markup Extensions #2
<Button>
<Button.Foreground>
<x:Static Member="SystemColors.ActiveCaptionBrush"></x:Static>
</Button.Foreground>
</Button>
- StaticExtension is a class
- Maybe used as complex attribute
Attached Properties
<Button Grid.Row=”1”>Ok</Button>
- Properties that apply to several controls but are defined in a different class
- Mostly used to control layout
- When a control is nested in container it gains additional features depending on the container
- E.g. Grid: choose grid cell for the current control
- Syntax: DefiningType.PropertyName
- Allows XAML parser to distinguish between attached property and normal property
- Attached properties not real properties - they are translated into method calls: Grid.SetRow(btn, 1);
Events
// <Button Click="cmdAnswer_Click"></Button>
private void cmdAnswer_Click(object sender, RoutedEventArgs e)
{
this.Cursor = Cursors.Wait;
// Dramatic delay...
System.Threading.Thread.Sleep(TimeSpan.FromSeconds(3));
AnswerGenerator generator = new AnswerGenerator();
txtAnswer.Text = generator.GetRandomAnswer(txtQuestion.Text);
this.Cursor = null;
}
- So far all attributes are mapped to object properties
- Attributes can also be used for event handlers
- Syntax: EventName="EventHandlerMethodName"
Layout
Intro
- Coordinate-based layouts in the past
- Possible in WPF but not common
- Mostly weblike flow layouts
- Show and hide content depending on screen size
- Internationalization
- In WPF there are different containers
- Each container has its own logic
WPF Layout
- Window can hold one single element
- Add container and place all elements inside the container
- Layout is defined by the container you use
- Principles
- Elements should not be exlicitely sized
- Limit size by setting maximum or minimum sizes
- Position not via screen coordinates
- Arranged by container based on size, order and other info
- Use margin for whitespace between elements
- Containers share space among children
- Containers can be nested
Layout Process
- 2 stages: measure and arrange
- Measure stage
- Containers loops through child elements
- Asks for preferred size
- Arrange state
- Container places the child in the appropriate position
- Sometimes element do not get all the preferred size
- Truncated to visible area
Layout Containers
- All layout containers are panels that derive from System.Windows.Controls.Panel class
- Panel class has three public properties
- Background: Brush used to paint the panel background. Must be set to a non null value if moue events should be received (e.g. transparent)
- Children: Collection of items stored in panel
- IsItemsHost: True if the panel is being used to show items from an ItemControl
Layout Containers #2
- StackPanel
- Places elements in a horizontal and vertical stack
- WrapPanel
- Places elements in a series of wrapped lines
- In horizontal orientation WrapPanel lays items out in a row from left to right and then next line
- In vertical orientation - top-to-bottom then next column
- DockPanel
- Aligns elements against an entire edge of the container
- Grid
- Arrange elements in rows and columns
- UniformGrid
- Table layout, cells same size
Layout Containers #3
- Canvas
- Allows positioning via absolute coordinates
- Similar to Windows Forms
- Several more specialized containers
- ToolbarPanel, ToolbarOverflowPanel
- VirtualizingStackPanel, etc.
StackPanel
- Arrange elements from top to bottom
- Each element as tall as necessary
- Stretched to fill full width of StackPanel
- Orientation="Horizontal"
- Allows to specify the orientation
<Window x:Class="StackPanel.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>
<Label>Stack up buttons</Label>
<Button>Test1</Button>
<Button>Test2</Button>
<Button>Test3</Button>
</StackPanel>
</Window>
Layout Properties
- Children of layout containers may specify needs via layout properties
- HorizontalAlignment
- Determines position of child element when there is extra horizontal space
- VeritcalAlignment
- Determine position when there is extra vertical space
- Margin
- Space around element
- Width and Height
- MinWidth/MinHeight and MaxWidth/MaxHeight
- Inherited from FrameworkElement
Alignment
<Window x:Class="StackPanel.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>
<Label HorizontalAlignment="Center">Stack up buttons</Label>
<Button HorizontalAlignment="Left">Test1</Button>
<Button HorizontalAlignment="Center">Test2</Button>
<Button HorizontalAlignment="Right">Test3</Button>
<Button>Test4</Button>
</StackPanel>
</Window>
- Default value: Stretch
Margin
<Window x:Class="StackPanel.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>
<Label HorizontalAlignment="Center">Stack up buttons</Label>
<Button HorizontalAlignment="Left" Margin="5">Test1</Button>
<Button HorizontalAlignment="Center" Margin="2,5,2,5">Test2</Button>
<Button HorizontalAlignment="Right">Test3</Button>
<Button>Test4</Button>
</StackPanel>
</Window>
- Add spacing around element
- Either single value or left, top, right, bottom
Dependency Properties
Intro
- WPF replaces ordinary .NET properties with a higher-level dependency property feature
- More efficient storage usage
- Support change notification
- And property value inheritance
- Ability to propagate default values down the element tree
- Basis for number of key WPF features
- Animation
- Data binding
- Styles, etc.
- Most of properties exposed by WPF elements are dependency properties
Defining Dependency Properties
public class FrameworkElement: UIElement, ... {
public static readonly DependencyProperty MarginProperty;
...
}
- Dependency properties can only be added to Dependency Objects
- Classes that derive from DependencyObject
- First define an object that represents the property
- Is an instance of the DependencyProperty class
- Must be static
- Information about DP needs to be available all the time
- Shared among classes
- Field that defines DP has usual name + Property at the end
- Must be readonly
- Can only be set in the static constructor
Registering a Dependency Property
static FrameworkElement() {
FrameworkPropertyMetadata metadata = new FrameworkPropertyMetadata(
new Thickness(), FrameworkPropertyMetadataOptions.AffectsMeasure);
MarginProperty = DependencyProperty.Register("Margin",
typeof(Thickness), typeof(FrameworkElement), metadata,
new ValidateValueCallback(FrameworkElement.IsMarginValid));
...
}
- Two steps
- Create FrameworkPropertyMetadata object to indicate what services you want to use with your dependency property (data binding, animation, and journaling)
- Next register property by calling DependencyProperty.Register() method
Registering a Dependency Property #2
- Need to supply few key properties
- Property name (Margin)
- Data type used by property (Thickness)
- Type that owns this property (FrameworkElement)
- FrameworkPropertyMetadata object with additional property settings (optional)
- Callback that performs validation for the property (optional)
- FrameworkPropertyMetadata mostly sets specific flags to provide additional information
Adding a Property Wrapper
public Thickness Margin
{
set { SetValue(MarginProperty, value); }
get { return (Thickness)GetValue(MarginProperty); }
}
- Final step is to write a usual .NET property
- Use SetValue and GetValue that are defined in the DependencyObject class
- Do not write any other code in wrapper properties, since other features in WPF may bypass the property wrapper
Using Dependency Properties
#include <stdio.h> // # marks a preprocessing directive
- Every DP supports change notification and dynamic value resolution
- No events are fired, instead OnPropertyChangedCallback() is triggered
References
Pro WPF 4.5 in C# (4th Edition)
Matthew MacDonald
Thank you for your attention!
WPF
By dinony
WPF
Windows Presentation Foundation
- 390