0% found this document useful (0 votes)
270 views56 pages

Fosler J., Boutler M. - WPF For Those Who Know Windows Forms

This document provides an overview of key concepts for developing Windows Presentation Foundation (WPF) applications for developers familiar with Windows Forms. It covers XAML basics like namespaces and element mapping, how to work with controls similar to Windows Forms, layout techniques, data binding, and resources. The document also provides code examples for common tasks like handling control events and accessing named elements from code.

Uploaded by

saurabh
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOC, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
270 views56 pages

Fosler J., Boutler M. - WPF For Those Who Know Windows Forms

This document provides an overview of key concepts for developing Windows Presentation Foundation (WPF) applications for developers familiar with Windows Forms. It covers XAML basics like namespaces and element mapping, how to work with controls similar to Windows Forms, layout techniques, data binding, and resources. The document also provides code examples for common tasks like handling control events and accessing named elements from code.

Uploaded by

saurabh
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOC, PDF, TXT or read online on Scribd
You are on page 1/ 56

WPF for those who know Windows Forms

Jessica Fosler & Mark Boulter


Microsoft Corp

XAML Application Basics......................................................................................................1


Learn XAML...................................................................................................................1
Some XAML you gotta know..........................................................................................1
Tools for Editing XAML..................................................................................................4
Application and MyApp.xaml.........................................................................................4
Form-ing Windows and looking at Controls.........................................................................6
Window equals Form.....................................................................................................6
Namespaces and other such details..............................................................................6
Controls.........................................................................................................................6
Child Controls/Elements..............................................................................................10
Control Visibility...........................................................................................................14
Dialog Boxes................................................................................................................14
Mappings of controls in the “Common Controls” Toolbox Tab...................................16
Mappings of controls in the “Containers” Toolbox Tab...............................................25
Mappings of controls in the “Menus and Toolbars” Toolbox Tab................................26
Input, Eventing and Mnemonics..........................................................................................27
Eventing and User Input...............................................................................................27
Specifying access keys/mnemonics............................................................................27
Layout and Locations.........................................................................................................28
Layout..........................................................................................................................28
RightToLeft (AKA RTL, Bidi) Support...........................................................................33
Scrolling and Scaling...................................................................................................33
Transforms...................................................................................................................33
Figuring out your location relative to other elements..................................................34
Beware the device-independent pixels.........................................................................34
Data Demystified.................................................................................................................34
Data..............................................................................................................................34
Databinding Walkthroughs...........................................................................................39
Advanced Databinding.................................................................................................43
Resources....................................................................................................................44
Using System Colors and x:Static................................................................................48
Styles, Templates and Triggers....................................................................................48
Multithreaded Applications..........................................................................................50
Settings........................................................................................................................50

Information is provided “as-is”, provides no warranties and confers no rights.


XAML Application Basics
Learn XAML
If you’ve seen “Avalon” demos, then you know that it is often developed with using a specialized
form of XML called XAML.

It is possible to write “Avalon” to the bare metal using code (C#, VB, or your favorite CLS-
Compliant-Language of choice), however the designers of the Avalon libraries have optimized the
“feel” of their APIs for XAML – sometimes this is just shortened to the word “markup”. Charles
Petzold has an interesting discussion here about when to use what.

Some XAML you gotta know

<!-- Window1.xaml -->


<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="WindowsApplication1.Window1"
Title="Main Window"
>

What is xmlns?
Definition from W3C:
XML namespaces provide a simple method for qualifying element and attribute names
used in Extensible Markup Language documents by associating them with namespaces
identified by URI references.

By bringing in custom xml namespaces, we essentially bring in another set of “valid” XML
element types and attribute names.

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
This pulls in the XML schema for the Windows Presentation Foundation itself. By setting
this as the default XML namespace, we can just create <Button> without prepending it
with anything silly like <wpf:Button>.

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
This brings in XAML keywords, markup extensions (the funny stuff you’ll sometimes see
in curly braces). Interesting x: stuff includes
“x:Key” for setting keys in a resource dictionary
“x:Static” for fetching statics off a CLR class
“x:Class” for associating a codebehind
“x:Type” for specifying a type
“x:Null” for setting something to null in XAML

x:Class="WindowsApplication1.Window1"
This helps the XAML compiler to find the associated code-behind – in this case it would
look for WindowsApplication1.Window1 as its codebehind file.
Title="Main Window"
Finally an easy one: this one sets the title for the window to say “Main Window”.

Bringing in your own objects to the XAML party


It is possible to create any CLR type within XAML. You just need to learn the equivalent of the
“using” statement in XAML.

<!-- Window1.xaml -->


<Window x:Class="WindowsApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WindowsApplication1"
>
<local:MyButton>Moo</local:MyButton>
</Window>

// Window1.xaml.cs
namespace WindowsApplication1 {
public class MyButton : System.Windows.Controls.Button {
}
}

Note that the use of “local” is a matter of choice – it’s what you’ll use to prefix your elements
from that namespace. We could have replaced all the “local” strings with “foo” or
“WindowsApplication1” and it would have worked.

Bringing in custom objects from another assembly


When you bring in an object from another assembly, you have to specify the particular assembly
in the xmlns assignment. As usual, you also have to add a reference to the assembly in your
Visual Studio project.

<!-- Window1.xaml -->


<Window x:Class="WindowsApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=System"
>
<ListBox>
<sys:String>One</sys:String>
</ListBox>
</Window>

Talking to Elements Defined in XAML From Code

If you name your elements in your XAML file, you can access them as if they were member
variables on the class.

<!-- Window1.xaml -->


<Window x:Class="WindowsApplication14.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WindowsApplication14"
>
<Canvas>
<TextBox Name="textBox1"></TextBox>
</Canvas>
</Window>

From code:
// Window1.xaml.cs
textBox1.Text = "Hello World!";

You can either write this code in the constructor, or you can use the “Loaded” event instead.

Option 1: Hooking onto the Loaded event from XAML

<!-- Window1.xaml -->


<Window x:Class="WindowsApplication14.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

Title="WindowsApplication14"
Loaded="OnWindowLoaded"
>
<Canvas>
<TextBox Name="textBox1"></TextBox>
</Canvas>
</Window>

// Window1.xaml.cs
private void OnWindowLoaded(object sender, RoutedEventArgs e) {
textBox1.Text = "Hello World!";
}
Option 2: Hooking onto the Loaded event from code

public Window1() {
InitializeComponent();
this.Loaded += new RoutedEventHandler(OnWindowLoaded);
}

void OnWindowLoaded(object sender, RoutedEventArgs e) {


textBox1.Text = "Hello World!";
}

Tools for Editing XAML


Microsoft Expression codenamed “Sparkle”
Visual Studio codename “Orcas” designer codenamed “Cider”
XamlPad
XamlCruncher (Petzold)

Application and MyApp.xaml

“Avalon” has three kinds of application styles – a simple Application (Window-based, just like
windows forms), a NavigationApplication (page based, just like Microsoft Money or a
website), and a DocumentApplication (specialized sub-set of NavigationApplication for
displaying content).
An “Avalon” application can either be run in two modes: Express (run from browser) and
Installed (behaves like classic Windows applications). Just like Windows Forms, “Avalon” works
with ClickOnce for installation.

Files in a simple Application

If you create a new “Windows Application (WPF)” in Visual Studio, you’ll get several files:

 MyApp.xaml
o Application declaration in xaml
 MyApp.xaml.cs or MyApp.xaml.vb, etc
o Application code behind – application startup events and so on
 Window1.xaml
o Window declaration in xaml
 Window1.xaml.cs or Window1.xaml.vb, etc
o Window code behind – event handlers and so on

MyApp.xaml and its codebehind file are most like the Program.cs from a C# Windows Forms
application. This is where you’ll put anything that applies to the entire application – typically you
may want to associate resources, styles to be shared between all your Windows in your
application.

Where is Application.Run?
Believe it or not, “Avalon” has an Application.Run too – to find it we need to talk about what
happens when you build XAML.

When you build Avalon takes the .xaml and generates a set of files that are then compiled in to
the exe. For <Name>.xaml the following are generated:

<Name>.baml
Binary version of the .xaml file. Compiled into the .exe as a resource

<Name>.g.cs (or .g.vb)


Partial class that is combined with <Name>.xaml.cs (or .vb). Contains
initialization code that does the following:

 Loads the baml resource to display the UI


 Wires up event handlers
 Wires up member variables to live objects (Button1 for example)

So the build is a two step process – firstly it generates this stuff, then it compiles and generates
an exe.

Peeking at MyApp.g.cs
[STAThread()]
public static int Main(string[] args) {
WindowsApplication22.MyApp app = new
WindowsApplication22.MyApp();
app.InitializeComponent();
return app.Run(args);
}

So if Main is in an automatically generated class how do I add stuff to Main?


You can hook the StartingUp event on Application to add custom logic.

<!-- MyApp.XAML -->


<Application x:Class="WindowsApplication22.MyApp"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Window1.xaml"
Startup="OnApplicationStartingUp"
>
<Application.Resources>

</Application.Resources>
</Application>

// MyApp.xaml.cs
public partial class MyApp : Application {
private void OnApplicationStartingUp(object sender,
StartupEventArgs e) {
if (e.Args.Length == 1 && e.Args[0] == "/?") {
MessageBox.Show("Help!");
}
}
}
Form-ing Windows and looking at Controls

We’ll start with a brief discussion of Forms and Windows, namespaces, then dive into Controls,
the Control hierarchy and a mapping of the Windows Forms controls to the new WPF ones.

Window equals Form


The new word for “Form” is “Window”. “Window” is a toplevel entity in Windows Presentation
Foundation. Unlike Form, the Window class cannot be morphed into a non-toplevel entity. You
cannot parent a Window to another Window in the system; this includes MDI.

MDI
According to Nick Kramer, PM on the WPF team, version 1 of “Avalon” will unfortunately not
include support for MDI. If you want to use MDI with Avalon, you can use use interop to display
WPF controls inside a Windows Forms application. His blog has some sample code to show how
to achieve this.

Additionally, you may consider structuring your program to use a NavigationWindow instead –
which is a built-in way of building inductive UIs.

NKramer: MDI Windows in Avalon

Namespaces and other such details


The Windows Forms technology lives in the System.Windows.Forms namespace and
System.Windows.Forms.dll. Its corresponding GDI+ based graphics libraries live in
System.Drawing namespace and System.Drawing.dll.

The base class for most controls in Windows Forms is System.Windows.Forms.Control.

The Windows Presentation Foundation lives in several namespaces, all starting for the most part
with “System.Windows” but never including the word “Forms”. PresentationCore (which includes
primitives such as UIElement and drawing constructs in System.Windows.Media*),
PresentationFramework (which includes most the standard controls), UIAutomationProvider,
UIAutomationTypes, and WindowBase(which includes the Dispatcher and supporting types) are
all stock references included in a typical application.
Controls
Controls in “Avalon” work quite a bit differently than
Controls in Windows Forms.

In Windows Forms, the System.Windows.Forms.Control


gives you access to three things: A chunk of screen to
paint itself and layout child controls, access to the
keyboard and access to the mouse.

In “Avalon”, the visual representation of the “chunk of


screen” is pluggable. There is a corresponding
“Template” for a control, which represents all the stuff
that should visually appear when the control is
rendered. In other words, instead of painting
rectangles and text in the OnPaint event for your
control, you specify rectangles and text in XML. (Note
there is still an OnRender method, however specifying
XAML is preferred.)

In “Avalon” there are a few fundamental types of


controls – in particular ContentControls and
ItemsControls.

ContentControls can have exactly 1 child element1[1],


where as ItemsControls can have multiple child
elements. The interesting thing with ContentControls is
that the 1 element can be a layout container, therefore
it’s like wishing for more wishes – as long as you add in
a layout panel you can put in as much content as you
like to a content control.

The canonical example of a content control is a button


with Image and Text. In Windows Forms, you would
drop on a button and set the Image property and set
the TextImageRelation to ImageBeforeText. In
“Avalon”, you would add a button, drop in a StackPanel
(the equivilant of a FlowLayoutPanel) and set the
Orientation to Horizontal. Within the StackPanel, you would add an <Image/> and a
<TextBlock/>.

ItemsControls include most of the controls we think of as containing items. (ListBox, ListView,
TreeView). This category is further classified into Selector controls – that is – controls whose
purpose it is in life to make a singular choice out of a list of options. The best example of a
selector is a ComboBox.

1[1]
Note that Window is a ContentElement, which is why the auto-generated code puts some sort
of layout panel as the direct child. E.g. A window could not directly contain two buttons.
What to pick as your base class?

PRS 431 discusses this topic, the summary is:

Can UserControl solve it?


UserControl does not support ControlTemplates. It directly derives from FrameworkElement. If
you do not want to support replacing the UI via Templating, this is a good place to start.
UserControl

Do I need a control?
Control supports ControlTemplates. If you’re a control vendor you’ll want to derive from some
sort of control. Design your functionality so that you can databind to properties rather than
depending on particular visuals to be present. In order to create properties that work with
templates and triggers, create DependencyProperties.

Can I just use a FrameworkElement?


FrameworkElement is stylable, however it does not give you the ability to layout child elements.

Scenario FrameworkElement Control UserControl


Design like an app No No Yes
Drawing primitives Yes No No
Can Reuse Controls Yes Yes Yes
Supports Control Templates No Yes No
Can be used directly in application Yes Yes Yes
Recommended as a base class Yes Yes No
Example Image, Track Button ColorPicker

PDC05: PRS431: WPF (“Avalon”): Building Custom Controls


A quick walkthrough of the object hierarchy

DispatcherObject – this base class specifies a that the object is not inherently thread safe – it
wants to be accessed on the same thread as its corresponding Dispatcher.

The “Dispatcher” is the equivalent of the “Message Pump” in User32 applications. As events
occur, the “Dispatcher” keeps track of all the things that need to be processed and organizes how
all the events get dispatched out to the relevant dispatcher objects.

DependencyObject – objects of this type know how to support a special kind of property called
a DependencyProperty. DependencyObjects can fish the values for DependencyProperties from
“Avalon”’s underlying propertystore using the GetValue and SetValue methods.

Using a DependencyProperty over a regular CLR property adds:


 automatic support for databinding (don’t need to support INotifyPropertyChanged on the
element)
 reduces the size of your element (as space will only be allocated if property is set)
 ability to animate the property
 participation in styles and templates
 use in triggers to say “when this property changes” change the style, template etc.
 Inheritance – can set the property on an outer tag and it applies to the children below.

Visual – As the name suggests, “visual” elements have “visual” representations. This class adds
basic mouse hit testing features basic transformation features, and the ability to add “visual”
children.

FrameworkElement – This class adds the ability to Style, bind to dependency properties, fish
into and apply resources from the Resource dictionary, have a notion of size (Height, Width etc),
show ContextMenus and supports ToolTip.

UIElement – This class adds quite a bit of the features that are similar to
System.Windows.Forms.Control: drag/drop, mouse, keyboard, focus.

Control – Adds the ability to control the layout of child elements via ArrangeOverride and
MeasureOverride. Font, Padding, Borders, Background information and TabStop also appear at
this level in the object hierarchy.

Most importantly: Adds the Template property, which allows you to dynamically replace the visual
elements that define the look and feel of the control.

ContentControl – Derives from Control. ContentControls only support one child element – but
this a control which supports adding more controls.

Window – Derives from ContentControl. This is the analog of “Form” in WPF. Because this is a
ContentControl, it can only hold one element – e.g. adding two buttons as direct children to a
Window causes an exception when compiling. This is why the designer adds a layout panel
(typically a Grid) as the immediate child of a window.

ItemsControl - Derives from Control. ItemsControls can support more than one child element.
ItemsControl supports grouping, databinding to a list, and replacing the layout by swapping
in/out the ItemsPanel.
Child Controls/Elements

We talked briefly about ItemsControls being able to hold more than one child control and
ContentControls being able to hold one child element.

Windows Forms and “Avalon” are really both tree representations

In Windows Forms, Controls can be added to Controls using the Control collection on Control. In
other words – you could add a Button to a Panel.Controls and the Panel to a Form.Controls
collection.

// Windows Forms
form.Controls.Add(panel);
panel.Controls.Add(button1);

If you think about this, it represents a logically represents a tree:

Form
Panel
Button1
Button2
Panel
Button3

This concept is similar “Avalon”. Elements can add to other elements.


<Window>
<Panel>
<Button>Button1</Button>
<Button>Button2</Button>
</Panel>
<Panel>
<Button>Button3</Button>
</Panel>
</Window>

Interpreting XAML content

If you notice, the content you can put inside a <Panel> tag is different than what you can put
inside a <Button> tag. If you were to write this in code you would say:

// “Avalon”
panel.Children.Add(button1);
button1.Content = “Button1”;

Obviously, there’s some magic glue that occurs to interpret the content of the panel differently
than the content of the Button. This happens to be an attribute specified on the top of the class
called “ContentPropertyAttribute” that says what property the Content of the XAML tag should be
represented as.

The Panel in “Avalon” happens to have [ContentProperty(“Children”)] specified, which means


that the content of the XAML will populate the “Children” property on the Panel.

In other words
<Panel>
<Button>Button1</Button>
</Panel>

Is shorthand for setting the Panel.Children property like so:


<Panel>
<Panel.Children>
<Button>Button1</Button>
</Panel.Children>
</Panel>
Or
Panel.Children.Add(button1)

The Button in “Avalon” happens to have [ContentProperty(“Content”)] specified, which means


that the content of the XAML will populate the “Content” property on the Button.

If you look at the Button.Content property (which comes from the ContentControl class), you can
see that any object can be assigned to it. In our simple case we’ve just assigned a string, but
you could put anything in.

Adding custom content to a Button.Content

Let’s say we have a class Book in our project


namespace WindowsApplication12
{
public class Book
{
private string author;
private string title;
public Book()
{
}
public string Author
{
get { return author; }
set { author = value; }
}
public String Title
{
get { return title; }
set { title = value; }
}
}
}
We can either directly create a button
Button button = new Button();
Book book = new Book();
book.Title = “Grapes of Wrath”
book.Author = “Steinbeck”;
button.Content = book;

Or create it in XAML – note how the properties can be set in XAML. For this to work, the Book
class has to have an empty constructor. 2[2]

<Button>
<local:Book Title="Grapes of Wrath" Author="Steinbeck"/>
</Button>

The result of this is

…which isn’t very interesting.

Much like the items in a System.Windows.Forms.ListBox, “Avalon” calls Object.ToString() to


represent the content of a button. If we want to change the result, we can override ToString() on
our Book object to return the Author and Title:

public override string ToString()


{
return Author + " - " + Title;
}

If you don’t want to override ToString(), then you can create a DataTemplate to represent the
Book. DataTemplates are a way of saying “Any time you see an element of type “Book” in the
XAML, represent it with the following UI…” For more information, see the “Data” section.

2[2]
Use the “Mapping” attribute to make “local:Book” a valid XAML tag. See “XAML you gotta
know” section for syntax.
What the ContentProperty maps to

Using the power of reflection, we can inspect what the ContentProperty is on some of the
FrameworkElements:

SWC.Panel : Children SWC.Primitives.Popup : Child


SWC.Canvas : Children SWC.Primitives.RepeatButton : Content
SWC.ContentControl : Content SWC.Primitives.StatusBar : Items
System.Windows.Window : Content SWC.Primitives.StatusBarItem : Content
System.Windows.Navigation.NavigationWindow SWC.Primitives.TabPanel : Children
: Content SWC.Primitives.ToolBarOverflowPanel : Children
SWC.AdornedElementPlaceholder : Child SWC.StackPanel : Children
SWC.Decorator : Child SWC.Primitives.ToolBarPanel : Children
SWC.Border : Child SWC.Primitives.UniformGrid : Children
SWC.Primitives.ButtonBase : Content SWC.RadioButton : Content
SWC.Button : Content SWC.RichTextBox : Document
SWC.Primitives.ToggleButton : Content SWC.ScrollViewer : Content
SWC.CheckBox : Content SWC.TabControl : Items
SWC.ItemsControl : Items SWC.TabItem : Content
SWC.Primitives.Selector : Items SWC.TextBlock : Inlines
SWC.ComboBox : Items SWC.TextBox : Text
SWC.ListBoxItem : Content SWC.ToolBar : Items
SWC.ComboBoxItem : Content SWC.ToolBarTray : Children
SWC.Primitives.MenuBase : Items SWC.ToolTip : Content
SWC.ContextMenu : Items SWC.TreeView : Items
SWC.DockPanel : Children SWC.TreeViewItem : Items
SWC.Primitives.DocumentViewerBase : SWC.Viewbox : Child
Document SWC.VirtualizingPanel : Children
SWC.DocumentViewer : Document SWC.VirtualizingStackPanel : Children
SWC.HeaderedContentControl : Content SWC.WrapPanel : Children
SWC.Expander : Content System.Windows.Documents.AdornerDecorator :
SWC.SinglePageViewer : Document Child
SWC.Grid : Children System.Windows.Documents.FixedPage : Children
SWC.GroupBox : Content System.Windows.Documents.PageContent : Child
SWC.GroupItem : Content System.Windows.Documents.TextFlow : Blocks
SWC.HeaderedItemsControl : Items System.Windows.Navigation.PageFunctionBase :
SWC.InkPresenter : Child Content
SWC.Label : Content System.Windows.Navigation.PageFunction<T> :
SWC.ListBox : Items Content
SWC.ListView : Items
SWC.ListViewItem : Content
SWC.Menu : Items
SWC.MenuItem : Items
SWC.Page : Content
SWC.Primitives.BulletPanel : Children
SWC.Primitives.GridViewColumnHeader :
Content
Control Visibility
There is a Visibility property which shows up on the UIElement class. The possible values of
“Visibility” are “Visible”, “Hidden”, and “Collapsed”.

Visibility=“Hidden” may not do what you expect – “Hidden” implies that the element should not
render but should continue to occupy the same space it would if it is “Visible”.

<DockPanel>
<Button DockPanel.Dock="Top">
Top1
</Button>
<Button Visibility="Hidden"
DockPanel.Dock="Top">
Top2
</Button>
<Button>Fill</Button>
</DockPanel>

As you can see there is a white gap where space for “Top2” button is reserved. If we switch to
Visibility = “Collapsed” the space is no longer reserved for “Top2”.

Visibility = “Hidden” can be handy for situations where you want to save space for an element
that may occasionally appear (say an error icon after a text box, etc).

<DockPanel>
<Button DockPanel.Dock="Top">
Top1
</Button>
<Button Name="Foo"
Visibility="Collapsed" DockPanel.Dock="Top">
Top2
</Button>
<Button>Fill</Button>
</DockPanel>
Dialog Boxes

The file dialogs can be found in Microsoft.Win32:


- OpenFileDialog – Microsoft.Win32.OpenFileDialog
- SaveFileDialog – Microsoft.Win32.SaveFileDialog
- FolderBrowserDialog – No Avalon equivalent, use Windows Forms FolderBrowserDialog

<Window x:Class="WindowsApplication14.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WindowsApplication14"
>
<Canvas>
<Button Click="Button_Click">Ok</Button>
</Canvas>
</Window>

private void Button_Click(object sender, EventArgs e) {


OpenFileDialog ofd = new OpenFileDialog();
if (ofd.ShowDialog() == true) {
MessageBox.Show(ofd.SafeFileName);
}
}

Mappings of controls in the “Common Controls” Toolbox Tab


Windows Windows Presentation Foundation
Forms
Button System.Windows.Controls.Button

Notes: ContentControl. For image property add in a stack


panel, an image element and a text element.

For cancel buttons, set IsCancel=”true”


For accept (OK) buttons, set IsDefault=”true”

<!--Window1.XAML-->
<Button Click="OnButtonClicked">Click me!
</Button>

// Window1.xaml.cs
private void OnButtonClicked(object sender,
EventArgs e){
MessageBox.Show("Clicked!");
}

CheckBox System.Windows.Controls.CheckBox

<!--Window1.XAML-->
<CheckBox IsChecked="True"
Checked="OnCheckedChanged" >Use this
option</CheckBox>
Windows Windows Presentation Foundation
Forms
// Window1.xaml.cs
private void OnCheckedChanged(object sender,
EventArgs e){
MessageBox.Show("CheckedChanged!");
}

Notes: ContentControl.
CheckedLis System.Windows.Controls.ListBox
tBox
Notes: ItemsControl. Use a DataTemplate to add a checkbox
to the ListBoxItems.
<UserControl
x:Class="WindowsApplication10.CheckedListBox"
xmlns="http://schemas.microsoft.com/winfx/
2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/
2006/xaml"
>
<UserControl.Resources>
<DataTemplate x:Key="checkedListBox">
<CheckBox IsChecked="{Binding
RelativeSource=/TemplatedParent/TemplatedParent
, Path=IsSelected, Mode=TwoWay}">
<ContentPresenter
Content="{TemplateBinding
Property=Content}"></ContentPresenter>
</CheckBox>
</DataTemplate>
</UserControl.Resources>

<UserControl.FixedTemplate>
<ListBox ItemTemplate="{StaticResource
checkedListBox}" ItemsSource="{Binding}"/>
</UserControl.FixedTemplate>
</UserControl>

// Sample usage populating the items via


DataBinding:
public partial class CheckedListBox :
UserControl {
public CheckedListBox() {
InitializeComponent();
this.DataContext = new string[] {
"one", "two", "three", "four" };
}

ComboBox System.Windows.Controls.ComboBox

<Window x:Class="WindowsApplication10.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/
Windows Windows Presentation Foundation
Forms
xaml/presentation"
xmlns:x=http://schemas.microsoft.com/winfx/
2006/xaml
Title="WindowsApplication10">
<Grid Name="someGrid">
<ComboBox>
<ComboBoxItem>One</ComboBoxItem>
<ComboBoxItem>Two</ComboBoxItem>
<ComboBoxItem>Three</ComboBoxItem>
<ComboBoxItem>Four</ComboBoxItem>
</ComboBox>
</Grid>
</Window>

Notes: ItemsControl, Selector. Because the items can display


richer element trees, it is far easier to add images to your items
in your combobox, where as in the old ComboBox you had to
do OwnerDraw.

The ComboBox has several “modes” of operation:


 SWF,ComboBoxStyle.DropDown: (default in Windows
Forms)
o Can type in new content into the text area of
the combobox.
o ComboBox.IsEditable=”true”

 SWF.ComboBoxStyle.DropDownList: (default in WPF)


o Can only pick items from the
o ComboBox.IsEditable = “false”
 SWF.ComboBoxStyle.Simple
o Use TextBox and ListBox instead

A form of AutoComplete is supported via the


IsTextSearchEnabled property, and the TextSearch.TextPath &
TextSearch.Text, but this is not the same as the “url”
completion AutoComplete in the WindowsForms combobox.

TextSearch is a feature that allows a user to quickly


navigate items in a collection by typing a string which
is prefix-matched against the “primary” string
representation of each item in the collection. In some
cases, this may feel similar to behavior achieved using
AccessKeys, but does not require the developer to call
out specific mnemonics for each item.

DateTimePi Notes: No equivalent in WPF. Use TextBox or Interop with


cker Windows Forms.

<Window x:Class="WindowsApplication10.Window1"
xmlns="http://schemas.microsoft.com/winfx/
2006/xaml/presentation"
Windows Windows Presentation Foundation
Forms
xmlns:x="http://schemas.microsoft.com/winfx/
2006/xaml"
Title="WindowsApplication10"
xmlns:wf="clr-
namespace:System.Windows.Forms;assembly=System.
Windows.Forms"
>
<Grid>
<WindowsFormsHost>
<wf:DateTimePicker></wf:DateTimePicker>
</WindowsFormsHost>
</Grid>
</Window>

Label System.Windows.Control.Label or TextBlock

Notes: ContentControl. In Windows Forms, to set a mnemonic


on the label you change the text to be “A&ddress” so that the
“d” will be underlined. The next control in the tab order will be
selected when “d” is pressed. In WPF you set the “Target” to
be the control you want to select, and use “_” to specify the
mnemonic: “A_ddress”.

To specify this in XAML, use


<Label Target="{Binding
ElementName=addressTB}">
A_ddress
</Label>
<TextBox Name="addressTB"></TextBox>
LinkLabel System.Windows.Documents.Hyperlink

<TextBlock>
This is a <Hyperlink>hyperlink!
</Hyperlink> You can also now do
<Bold>bold</Bold> and <Italic>italic</Italic>
inline as well!
</TextBlock>

Notes: Use a Hyperlink tag within a TextBlock. Unlike


LinkLabel, Hyperlink is not a full-fledged control.

ListBox System.Windows.Controls.ListBox

<ListBox>
<ListBoxItem>One</ListBoxItem>
<ListBoxItem>Two</ListBoxItem>
<ListBoxItem>Three</ListBoxItem>
Windows Windows Presentation Foundation
Forms
</ListBox>

Notes: ItemsControl. Because the ListBox is far more flexible


than the System.Windows.Forms.ListBox (which was mainly
designed to display strings only), this control is far more useful
in “Avalon”.

Because the items can display richer element trees, it is far


easier to add images to your items in your listbox, where as in
the old ListBox you had to do OwnerDraw.

There are several properties of major interest to the ListBox:

Items – specifies the items to display in the listbox.

ItemsSource – specifies some sort of collection that will


represent the contents of the listbox (aka databinding)

ItemsTemplate – specifies a DataTemplate that can be used


to generate the UI for the items in the ItemsSource. (e.g. for
every Person in the People collection generate an image, a text
block for the first name, a text block for the last name).

ItemsPanel – specifies a way to create an alternate layout for


the listbox – instead of having the items appear one after the
other

Note that you can either use Items OR use ItemsSource,


using Items directly trumps the databinding. (Note stuff in the
middle of the <ListBox> XAML tag populates the Items
collection3[3] – so this would break databinding.)

In other words, the following code will throw as it specifies


both something for the Items collection and :

<!-- Bad XAML, specifies both


ListBox.ItemsSource and ListBox.Items -->
<ListBox ItemsSource="{Binding}">
<ListBoxItem></ListBoxItem>
</ListBox>

ListView System.Windows.Controls.ListView

Notes: ItemsControl. In WPF, derives from ListBox.


VirtualMode is supported by default when the
ItemsPanel=VirtualizedItemsPanel.

Without specifying a something special in the “View” the


ListView looks just like a ListBox.

3[3]
For more information see section on Child Controls/Elements.
Windows Windows Presentation Foundation
Forms
<ListView>

<ListViewItem>ListViewItem1</ListViewItem>

<ListViewItem>ListViewItem2</ListViewItem>

<ListViewItem>ListViewItem3</ListViewItem>

<ListViewItem>ListViewItem4</ListViewItem>
</ListView>

To get it to act more like the old ListView (LargeIcon,


SmallIcon, Details), use the View property to specify how you
want the control to layout.

Sample - Building up details view


Column headers in the ListView are specified in the
ListView.View, which is set to be a GridView.

Note DisplayMemberPath is DisplayMemberBinding in


newer builds of WPF.

<Window
xmlns="http://schemas.microsoft.com/winfx/
2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/200
6/xaml"
x:Class="WindowsApplication10.Window1">

<Window.Resources>
<XmlDataProvider x:Key="EmployeeData"
XPath="/EmployeeData">
<EmployeeData xmlns="">
<Employee>
<FirstName>Jesper</FirstName>
<LastName>Aaberg</LastName>
<FavoritePet>Fish</FavoritePet>
</Employee>
<Employee>
<FirstName>Dominik</FirstName>
<LastName>Pahiha</LastName>
<FavoritePet>Cat</FavoritePet>
</Employee>
</EmployeeData>
</XmlDataProvider>
</Window.Resources>
Windows Windows Presentation Foundation
Forms
<StackPanel>
<ListView ItemsSource="{Binding
Source={StaticResource EmployeeData},
XPath=Employee}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Margin="0,20,0,0">
<ListView.View>
<GridView>
<GridViewColumn Header="First Name"

DisplayMemberPath="{Binding
XPath=FirstName}" />
<GridViewColumn Header="Last Name"

DisplayMemberPath="{Binding XPath=LastName}" />

<GridViewColumn Header="Favorite Pet"

DisplayMemberPath="{Binding
XPath=FavoritePet}"/>
</GridView>
</ListView.View>
</ListView>
</StackPanel>
</Window>

MaskedTex System.Windows.Controls.TextBox
tBox
Notes: No direct equivalent in WPF. You may be able to
validate input using the
System.ComponentModel.MaskedTextProvider. (I’ve not tried
this). Add references to WindowsFormsIntegration.dll from
program files\reference assemblies and System.Windows.Forms
from the .net tab.

<Window x:Class="WindowsApplication10.Window1"

xmlns="http://schemas.microsoft.com/winfx/2006/
xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/200
6/xaml"
Title="WindowsApplication10"
xmlns:wf="clr-
namespace:System.Windows.Forms;assembly=System.
Windows.Forms"
>
<Grid>
<WindowsFormsHost>
<wf:MaskedTextBox></wf:MaskedTextBox>
Windows Windows Presentation Foundation
Forms
</WindowsFormsHost>
</Grid>
</Window>
MonthCale Notes: No equivalent in WPF. Interop with Windows Forms.
ndar Add references to WindowsFormsIntegration.dll from program
files\reference assemblies and System.Windows.Forms from
the .net tab.

<Window x:Class="WindowsApplication10.Window1"

xmlns="http://schemas.microsoft.com/winfx/2006/
xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/200
6/xaml"
Title="WindowsApplication10"
xmlns:wf="clr-
namespace:System.Windows.Forms;assembly=System.
Windows.Forms"
>
<Grid>
<WindowsFormsHost>
<wf:MonthCalendar></wf:MonthCalendar>
</WindowsFormsHost>
</Grid>
</Window>

NotifyIcon Notes: No equivalent in WPF. Continue to use Windows Forms


for this.
NumericUp System.Windows.Controls.TextBox
Down
Notes: No direct equivalent in WPF. Add buttons and databind
to your TextBox.
PictureBox System.Windows.Controls.Image

Notes: FrameworkElement. Uses a different kind of syntax to


specify the image location.
Instead of
pictureBox.Image = new Bitmap(typeof(Form), “foo.bmp”)
Use
<image source=”/Foo.bmp”/>
ProgressBa System.Windows.Controls.ProgressBar
r
Notes: RangeBase. Does not support marquee.

<ProgressBar
Value="50"/>
Windows Windows Presentation Foundation
Forms
RadioButto System.Windows.Controls.RadioButton
n
Notes: ToggleButton.

<StackPanel>
<RadioButton>One</RadioButton>
<RadioButton>Two</RadioButton>
<RadioButton>Three</RadioButton>
</StackPanel>

If you want RadioButtons to participate in the same “Group”


when parented to different panels, use
GroupName=”myGroup”.

RichTextBo Notes: The RichTextBox does not directly support RTF.


x
<RichTextBox>
<FlowDocument>
<Paragraph>This is paragraph
one.</Paragraph>
<Paragraph>This is paragraph
two.</Paragraph>
</FlowDocument>
</RichTextBox>

TextBoxes only accept plain text. But Text, TextPanel, and


RichTextBox may contain any combination of
 Unicode text.
 UIElement. Image, a nested Text, etc.
 ContentElement. LineBreak, etc.
 TextElement. Bold, Paragraph, etc – content that
spans other content. TextElements like Bold (anything
that derives from Inline) are essentially platforms for
DependencyProperties applied to spanned content.
TextElements like Paragraph (things that derive from
BlockElement) may hold property values, but always
provide structural information used by the layout
engine.

The RichTextBox operates on top of a Document object, which


allows you to manipulate the text in far more powerful ways
than what was exposed in Windows Forms.

That said it’s more difficult to work with. To load in text from a
file:
RichTextBox rtb = new RichTextBox();
string text = File.OpenText(@"c:\temp\
foo.txt").ReadToEnd();
rtb.Document.Blocks.Clear(); //if you want to
clear before adding text
rtb.Document.Blocks.Add(new Paragraph(new
Windows Windows Presentation Foundation
Forms
Run(text)));

RichTextBox and TextBox support spell checking via the


IsSpellCheckEnabled property. Like Windows Forms, TextBox
has AcceptsReturn and AcceptsTab properties.
TextBox System.Windows.Controls.TextBox

Notes: Supports only plain text.

<TextBox>Some text!</TextBox>

RichTextBox and TextBox support spell checking via the


IsSpellCheckEnabled property. Like Windows Forms, TextBox
has AcceptsReturn and AcceptsTab properties. The TextBox
can be made readonly via the IsReadOnly property.
ToolTip System.Windows.Controls.ToolTip

Notes: You can directly set the ToolTip property on the control
<Button>
<Button.ToolTip>
Hello World!
</Button.ToolTip>
</Button>
TreeView System.Windows.Controls.TreeView

Notes: When using a TreeView and DataBinding be sure to


use the HeirarchicalDataSource.

<TreeView>
<TreeViewItem Header="1">
<TreeViewItem Header
="1.1"/>
<TreeViewItem Header
="1.2"/>
</TreeViewItem>
<TreeViewItem Header="2">
<TreeViewItem Header
="2.1"/>
</TreeViewItem>
</TreeView>

WebBrows Notes: No direct equivalent in WPF. HTML can be statically


er rendered as the when assigned as the Source of a Frame.

<Frame Source ="http://www.msn.com"/>

If you want JavaScript/DOM support, use WebBrowser in a


WindowsFormsHost. In the December CTP there is a bug
preventing directly parenting WebBrowser to a
WindowsFormsHost – the easiest solution is to wrap win a
Windows Windows Presentation Foundation
Forms
UserControl. Add references to WindowsFormsIntegration.dll
from program files\reference assemblies and
System.Windows.Forms from the .net tab.

<Window x:Class="WindowsApplication10.Window1"

xmlns="http://schemas.microsoft.com/winfx/2006/
xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/200
6/xaml"
Title="WindowsApplication10"
xmlns:wf="clr-
namespace:System.Windows.Forms;assembly=System.
Windows.Forms"
Height="378" Width="392">
<Grid>
<WindowsFormsHost>
<wf:WebBrowser
Url="http://www.msn.com"></wf:WebBrowser>
</WindowsFormsHost>
</Grid>
</Window>
Mappings of controls in the “Containers” Toolbox Tab
Windows Forms Windows Presentation Foundation
FlowLayoutPanel System.Windows.Controls.StackPanel, for wrapping scenarios use
System.Windows.Controls.WrapPanel

Notes: See Layout section for samples.


GroupBox System.Windows.Controls.GroupBox

Notes: HeaderedContentControl
<GroupBox Header="Group Box Title">
</GroupBox>
Panel System.Windows.Controls.Canvas

Notes: See Layout section for samples. There is a “Panel” control in “Avalon”, it
is the base class of all Layout containers – StackPanel, Canvas, DockPanel, Grid,
etc.
SplitContainer Grid with GridSplitter
TabControl System.Windows.Controls.TabControl

Notes: Selector. Use TabItem with TabControl.

<TabControl SelectionChanged="OnTabChanged">
<TabItem Name="tab1" Header="Tab 1 Title" >
<TextBox>TabPage1</TextBox>
</TabItem>
<TabItem Name="tab2" Header="Tab 2 Title">
<TextBox>TabPage2</TextBox>
</TabItem>
</TabControl>

private void OnTabChanged(object sender, EventArgs e){


TabControl tabControl = sender as TabControl;
if (tabControl != null) {
if (tabControl.SelectedItem == tab1) {
//...
}
}
}
TableLayoutPanel System.Windows.Controls.Grid

Notes: See Layout section for samples

Mappings of controls in the “Menus and Toolbars” Toolbox Tab


Windows Forms Windows Presentation Foundation
ContextMenuStrip ContextMenu
MenuStrip Menu
StatusStrip StatusBar
ToolStrip ToolBar
ToolStripContainer ToolBarTray
Input, Eventing and Mnemonics
Eventing and User Input

Just as Windows Forms had the need to pre-process input from mouse, keyboard, etc, so does
“Avalon”. “Avalon” has re-used the concept of “tunnel” and “bubble”ed events from DHTML.

Bubbling event – starts at the element that raised the event, then goes up the parent chain.
Tunneling event – starts at the topmost element, then works its way to the element that
started the commotion

RoutedEvents usually come in pairs, e.g. PreviewMouseDown and MouseDown. The “Preview”
events are the “Tunnel” versions, as it allows the parents to preview the event before the child
element. …and necessarily, the follow-on event is the “Bubble” version. An alternate way to
handle events in WPF is through the use of commanding.

For more information on events, handling mouse and TextInput, read chapter 3 of Programming
Windows Presentation Foundation by Chris Sells & Ian Griffiths.

Specifying access keys/mnemonics

Use “_” to specify the access key instead of “&”

<Menu DockPanel.Dock="Top">
<MenuItem Header="File">
<MenuItem Header = "E_xit" Click="OnExitClicked"/>
</MenuItem>
</Menu>

For a Label, use the Target property to specify the UIElement should activate when the
mnemonic is pressed

<Window x:Class="WindowsApplication10.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WindowsApplication10"
Width="200"
Height="120"
>
<Grid Margin="9">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>

<Label Target="{Binding ElementName=addressTB}"


Grid.Column="0">A_ddress</Label>
<TextBox Name="addressTB" Grid.Column="1"
VerticalAlignment="Top"/>
<Button HorizontalAlignment="Right" Grid.Column="1"
VerticalAlignment="Bottom">_Ok</Button>
</Grid>
</Window>
Layout and Locations
Layout
In Windows Forms 1.0 and 1.1 there was really only one “layout engine”: dock and anchor
layout. In Windows Forms 2.0, the TableLayoutPanel and FlowLayoutPanel were added.

Windows Forms Windows Presentation Foundation


Anchor Layout – Absolute positioning from top Canvas
left corner of parent (Anchor= Top|Left)
Anchor Layout – Relative positioning (all other Grid
anchor combinations)
Dock Layout (Dock = DockStyle.Left, etc) DockPanel
FlowLayoutPanel StackPanel, WrapPanel
TableLayoutPanel Grid

Absolute Positioning

In Windows Forms, you can absolutely position controls by specifying the Location property. This
controls the distance between the parent’s top left corner and the control’s top left corner.
int x = 10;
int y = 20;
button.Location = new Point(x,y);

There are several ways to specify absolute positioning in Avalon.

Canvas
The Canvas control allows you to position a control at a fixed pixel coordinate. The Canvas
provides “Attached Properties” for specifying Canvas.Top, Canvas.Left. As of the December
CTP, it looks like specifying Canvas.Right, Canvas.Bottom does not change the size of the item.

<Canvas>
<Button Canvas.Top="10" Canvas.Left="20"></Button>
</Canvas>

Grid
The Grid control, much like its cousin the System.Windows.Forms.TableLayoutPanel is far more
flexible for situations where the controls are likely to grow and shrink and shift around adjacent
controls. Unlike TableLayoutPanel, the Grid can hold more than one control within a cell.

Like the TableLayoutPanel, you can specify absolute positioning within a cell by using the Margin
property on the element.

Margin is a representation of space outside of a control. In Windows Forms this is of type


System.Windows.Forms.Padding, in “Avalon” this is represented as System.Windows.Thickness.
Both classes have constructors that fill in Left, Top, Right, Bottom or (LTRB) as well as a
constructor that takes a single value that sets the distance uniformly. If you’re hand coding in
XAML this is handy to remember, I use “letter b” to remember it.
Specifying the Margin, we can scooch in 10px to the left and 20px from the top.

<Window ...>
<Grid>
<Button Margin="10,20,0,0"></Button>
</Grid>
</Window>

However the Button is currently set to stretch across


the entire cell. To resolve this, we can set the
HorizontalAlignment of the button from Stretch to Left,
and the VerticalAlignment of the button from Stretch to
Top.

<Grid>
<Button Margin="10,20,0,0"
VerticalAlignment="Top"
HorizontalAlignment="Left"/>
</Grid>

Relative Positioning

All other forms of anchoring can be achieved using the Grid control and combinations of Margin,
VerticalAlignment, HorizontalAlignment and (if there are multiple rows and columns)
Grid.RowSpan and Grid.ColumnSpan.

Say we want a button to be 100px wide – then as the dialog stretches, the button
should grow too. In Windows Forms, we would set the Location of the button, then
set its anchor to Top | Left | Right.
Win Forms “Avalon” “Avalon” Scenario
Anchors Alignments Margins to set
T L R B Horiz Vert Margin Behavior
Center Center Centered within the parent
T Center Top Top Centered horizontally, a fixed position away from the top
L Left Center Left Centered vertically, aligned to the left
T L Left Top Top, Left Fixed position relative to the upper left hand corner
R Right Center Right Centered vertically, aligned to the right
T R Right Top Top, Right Fixed position relative to the upper right hand corner
L R Stretch Center Left, Right Stretched horizontally, vertically centered
T L R Stretch Top Top, Left, Right Stretched horizontally, a fixed position away from the top
B Center Bottom Bottom Centered horizontally, a fixed position from the bottom
T B Center Stretch Top, Bottom Centered horizontally, stretched vertically
L B Left Bottom Left, Bottom Fixed position relative to the bottom left hand corner
T L B Left Stretch Top, Left, Bottom Fixed position from the left, stretched vertically
R B Right Bottom Right, Bottom Fixed position relative to the bottom right hand corner
T R B Right Stretch Fixed position from the right, stretched vertically
L R B Stretch Bottom Left, Right, Bottom Stretched horizontally, fixed position from the bottom
T L R B Stretch Stretch Top, Left, Right, Bottom Stretched horizontally and vertically
In the “Avalon” Grid, we can achieve this by horizontally stretching the control as if we’re going
to fill up the entire cell, then specifying a margin to say how far from the edge of the cell the
control should be.

<Window Width ="300" Height ="300" ...>


<Grid>
<Button Margin="10,20,190,0"
VerticalAlignment="Top" HorizontalAlignment="Stretch"/>
</Grid>
</Window>

For a complete mapping of anchors to the Grid, see the following table:

Dock Layout

In Windows Forms, there are six DockStyles: None, Top, Bottom, Left, Right, Fill. When a control
is Dock’ed to a side, it stretches across the entire length of the side. So a button Dock=Dock.Top
would stretch across the entire width of the Form.

The DockPanel in “Avalon” is pretty similar to the Dock property in Windows Forms. There’s one
catch: DockStyle.Fill and no DockStyle.None work differently.

By default in “Avalon”’s DockPanel, there’s a property called LastChildFill, which is set to true.
This means the last child added to the DockPanel will fill up the remaining space.

So consider this code:


<DockPanel>
<Button
DockPanel.Dock="Left">Left</Button>
<Button
DockPanel.Dock="Right">Right</Button>
<Button
DockPanel.Dock="Top">Top</Button>
<Button DockPanel.Dock="Bottom">Bottom</Button>
</DockPanel>

The Bottom button, as it was added last, will be treated as if it is set to the old DockStyle.Fill.

We can fix this by setting LastChildFill = false:

<DockPanel LastChildFill="False">
<Button
DockPanel.Dock="Left">Left</Button>
<Button
DockPanel.Dock="Right">Right</Button>
<Button DockPanel.Dock="Top">Top</Button>
<Button DockPanel.Dock="Bottom">Bottom</Button>
</DockPanel>
The Dock panel additionally has the ability to not stretch things
from edge to edge. If you specify the Width or Height or
HorizontalAlignment or VerticalAlignment, then the control will no
longer stretch.

<DockPanel LastChildFill="False">
<Button DockPanel.Dock="Top" Width="80">Top</Button>
<Button DockPanel.Dock="Top" Width="100">Top</Button>
<Button DockPanel.Dock="Top" Width="120">Top</Button>
</DockPanel>

StackPanel / FlowLayoutPanel

StackPanel is quite a bit like FlowLayoutPanel. It uses the Orientation property to specify a
Vertical or Horizontal flow. Unlike the FlowLayoutPanel, the StackPanel stretches the items
(same behavior as the DockPanel). The same strategy of using Width, Height,
HorizontalAlignment and VerticalAlignment will prevent stretching across the StackPanel.

<StackPanel Orientation="Vertical">
<Button Width="100" HorizontalAlignment="Left">Button1</Button>
<Button Width="100" HorizontalAlignment="Left">Button2</Button>
<Button Width="100" HorizontalAlignment="Left">Button3</Button>
<Button Width="100" HorizontalAlignment="Left">Button4</Button>
</StackPanel>

To wrap controls, use the WrapPanel class.

Grid / TableLayoutPanel
We’ve already talked a little bit about the grid – however we haven’t talked about Rows and
Columns. The equivilant of TableLayoutPanel.RowStyles and TableLayoutPanel.ColumnStyles for
the Grid is the RowDefinitions and ColumnDefinitions.

TableLayoutPanel Grid What it does


Column/RowStyle Column/RowDefinition
RowStyle(SizeType.Absolute, 100) <RowDefinition Fixed space of 100px
Height=“100”/>
RowStyle(SizeType.Percent, 100) <RowDefinition Height=“*”/> Fill up as a percentage of
remaining space
RowStyle(SizeType.Auto) <RowDefinition Row should size to fit the
Height=“Auto”/> contents

The thing to call out here is the “*”, which is a way of dividing out
remaining space in a table proportionally. If you have two
columns, one set to “2*” and the other to one star or “*”, then
the first column will be 2/3 the space and the second column will
be 1/3 the space.

<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"></ColumnDefinition>
<ColumnDefinition Width="1*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0">Button1</Button>
<Button Grid.Row="0" Grid.Column="1">Button2</Button>
</Grid>

Like the TableLayoutPanel, the space allocation is like so:


1. Fixed sized columns
2. Auto sized columns
3. Remaining space divided up into percentage or “*” columns

The Grid has a very helpful debugging feature: ShowGridLines = true. This can be toggled to
show where the Rows and Columns line up.

In addition to the three column/row definition types, there is a concept of a SharedSizingGroup.


Setting a SharedSizingGroup on a Column or Row Definition will keep the Row/Column a uniform
size with another Column/Row. A sample can be found here.

Advanced Layout APIs

Windows Forms has the concept of being able to arrange child controls in the OnLayout event or
by plugging in a new LayoutEngine. The equivilant “Avalon” concept is overriding the
“ArrangeOverride” method.

Windows Forms 2.0 added the concept of AutoSize and GetPreferredSize to Control. The
equivalent “Avalon” concept is overriding the “MeasureOverride” method. There are caveats to
overriding this method – if you want a child element to be considered for layout, you must call
“Measure” on it.

Windows Forms concepts:


1.0/1.1: Wonders of Windows Forms Layout
2.0: Windows Forms 2.0 Layout FAQ

Here are some videos to explore in more depth:


MSDN TV: Special Holiday Episode II: Avalon Layout Basics
PDC05: PRS329: WPF (“Avalon”): Building User Interface with Advanced Layout
Techniques
HenryH: Creating a Multi-Column ListBox

RightToLeft (AKA RTL, Bidi) Support


This is covered in Bidirectional Features of WPF. The equivalent of the RightToLeft property is
FlowDirection.

Scrolling and Scaling


To use scrolling use ScrollViewer.

<Window x:Class="WindowsApplication14.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WindowsApplication14"
>
<ScrollViewer>
<Button Height="400">Ok</Button>
</ScrollViewer>
</Window>

To scale your contents use ViewBox.

<Window x:Class="WindowsApplication14.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

Title="WindowsApplication14"
>
<Viewbox>
<Button Click="Button_Click">Ok</Button>
</Viewbox>
</Window>

Transforms
In WPF, there are two major kinds of transforms – LayoutTransforms and RenderTransforms.
These serve to help scale, rotate your control to your heart’s content. The LayoutTransform
occurs at layout time and impacts layout. The RenderTransform occurs when painting, and
does not impact the layout.

See Petzold’s blog article and sample on transforms.

Figuring out your location relative to other elements


In Windows Forms, you could always use the Location property to figure out the x,y distance
from the control’s parent’s origin (in most cases, this is the Top Left of the Parent’s client
rectangle). Since differing layout engines use different properties (Margin, Horizontal and
Vertical Alignment) a location property doesn’t make sense for WPF. Additionally, because you’re
likely to be heavily nested with controls within controls – we need something more powerful.

<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="CiderWindowsApplication132.Window1"
Title="Main Window"
Loaded="Window1_Loaded"
>

<Grid>
<Button Name="button1" Width="75" Height="23"></Button>
</Grid>
</Window>

void Window1_Loaded(object sender, RoutedEventArgs e) {


// get the button's location relative to the window
Point windowRelativePoint =
button1.TranslatePoint(new Point(0, 0), this);
button1.Content = windowRelativePoint.ToString();
}
If you don’t know your parent, you can use the VisualTreeHelper.GetParent to get it.

Beware the device-independent pixels


The “pixels” in WPF are actually 1/96 of an inch. Kinda-sorta. Petzold describes this well in his
blog. There’s more info about this subject on MSDN. If you need to translate to actual screen
coordinate pixels you can use PointToScreen.
Data Demystified
Data
You could get away without knowing databinding before, but you really need to understand it in
order to take full advantage of WPF (as Charles Petzold describes). In addition to being used in
the classical sense (pulling data from a database, coupling two disparate pieces of UI to work
against the same data), data binding is now used extensively to set properties on controls.

Understanding the basics of databinding is a key to success in the XAML world.

Understanding bindings in Windows Forms and how they map to “Avalon”

Let’s create a class called Book4[1], which we’ll use for databinding.

public class Book {


private string author;
private string title;

public Book(string author, string title) {


this.author = author;
this.title = title;
}
public string Author {
get { return author; }
set { author = value; }
}
public string Title {
get { return title; }
set { title = value; }
}
}

If you think about setting up simple databinding in windows forms:

// Windows Forms
TextBox textBox = new TextBox();
this.Controls.Add(textBox);

Book book = new Book("Steinbeck", "Grapes of Wrath");

Binding textAuthorDataBinding = new Binding(


"Text", // Name of property on textbox to bind to
book, // object to bind to. (DataSource)
"Author"); // Name of property on book. (DataMember)

textBox.DataBindings.Add(textAuthorDataBinding);

The binding object glued together several pieces of information:

4[1]
For brevity, this class does not support change notification – it should technically implement
INotifyPropertyChanged (preferred) or add AuthorChanged and TitleChanged events so that as
the Author and Title properties are changed whatever is bound to these properties are also
updated.
the property to set on the target control: TextBox.Text
the source of data: book
the property to access on the source of data: book.Author

Not so suprisingly, the problem space has not changed – while “Avalon” has a different way of
specifying it, “Avalon” bindings require the same three pieces of information.

In “Avalon”, there are several ways of setting up bindings, but for examples sake lets compare
the syntax of the two:

<!-- Avalon pseudocode -- !>


<TextBox Text=”{Binding Source=’some object’ Path=’some property name on the object’}”>

// Windows Forms
Binding textAuthorDataBinding = new Binding(
"Text", // Name of property on tb to bind to
book, // object to bind to (DataSource)
"Author"); // Name of property on book. (DataMember)

The {Binding} markup extension


As you see above, “Avalon” has introduced a special syntax called a “markup extension” to
represent their binding object. The Binding object has several ways of specifying a “data
source”, and in fact several ways to specify a “data member”. We will walk through several
scenarios and how to specify the “data source” and “data member” information to correctly fish
out data.

The DataContext property


Before we can go much further, we should talk about the DataContext property.

The data context is much like Windows Forms’ DataSource property – it can represent an object
or a list of objects for use in databinding. In “Avalon”, DataContext has a twist: the DataContext
is inherited to all child elements – setting the DataContext on “Window” means that all the
buttons and labels and listboxes can automatically look at the same source of data. A
DataContext can be set on any FrameworkElement or FrameworkContentElement, which will
trump the DataContext set on the parent element.

Kinds of data sources


“Avalon” can databind to:

Any CLR object - One can bind to properties, sub properties as well as indexers on a CLR object.
The binding looks for properties etc using
 Reflection - uses reflection and propertyInfo to get values of properties
 CustomTypeDescriptor - If the object implements ICustomTypeDescriptor, the bindings
uses this interface to get the values for the properties. This is useful, when the object
does not have a static set of properties, but the properties are determined dynamically.

In order for the data to “refresh” when the property changes, the CLR object should consider
implementing INotifyPropertyChanged (preferred) or adding a matching event for the property:
e.g. for a public string Foo { get; set; } create a public event EventHandler FooChanged;
XmlNode – it is possible to databind to a fragment of XML (XML data island) or an entire XML file
using the XmlDataProvider.

ADO.Net Data Table – it is possible bind to fields on the Row of a DataTable as well as walk
relationships in an ADO.Net DataSet from one table to another. This is done using the
ICustomTypeDescriptor implementation on DataView.

Dependency Object – it is possible bind to DependencyPropererties on other DependencyObjects.

Specifying sources of data in {Binding}


The DataContext can be used as the default source of data, that is if an element, or an element’s
parent has a DataContext assigned, then the Binding object just picks that up as the object to
bind against.

If you want to bind to something other than what’s currently stuffed in the DataContext, you can
set the data source explicitly. This is called an Explicit Data Source, because you’re not using
the inherited stuff from the DataContext.

Source versus ElementName versus RelativeSource


Source Explicitly sets the object to databind to, trumping what’s already been
inhertited from the DataContext.

ElementName Useful for binding the property on one element to another.

E.g. Binding textBox1.Text to button1.Content.


<TextBox Name="textBox1"/>
<Button
Content="{Binding ElementName=textBox1, Path=Text}"/>

RelativeSource Useful for databinding in a ControlTemplate or a Style

From MSDN

Member name Description

FindAncestor Refers to the ancestor in the parent chain of the data-bound


element. You can use this to bind to an ancestor of a specific type
or its subclasses. This is the mode you use if you want to specify
AncestorType and/or AncestorLevel. 
PreviousData Allows you to bind the previous data item in the list of data items
being displayed. 
Self Refers to the element on which you are setting the binding and
allows you to bind one property of that element to another
property on the same element. 
TemplatedParen Refers to the element to which the template (in which the data-
t bound element exists) is applied. 
Fishing out the part of the data you actually want to use
Obviously if a listbox and a label are pointing at the same object for their data, they’ll want to
display different things. There are several ways to fish out the exact data you want.

The rules for specifying “Path=” in a Binding markup extension

Here’s a breakdown of the rules for parsing PropertyPath syntax from MSDN:

Use it for specifying the property to bind to


 This is the simplest case, “{Binding Path=Title}”
Use it for specifying a subproperty
 To get the length of the Title string in C#, you would int length = book.Title.Length.
That’s “{Binding Path=Title.Length}”
Use it to access one element in a list
 To always databind to the title of the first book in the list of books, {Binding
Path=[0].Title}

For more info consult the PropertyPath XAML syntax.

Sample: Setting the DataContext in code


Lets add two books to a list and show how to set up the DataContext.

<Window x:Class="WindowsApplication14.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WindowsApplication14"
Loaded="OnWindowLoaded"
>
<DockPanel>
<TextBox DockPanel.Dock="Top"
Text="{Binding Path=Author}"/>
<ListBox ItemsSource="{Binding}"
IsSynchronizedWithCurrentItem="True"/>
</DockPanel>
</Window>
public partial class Window1 : Window {
// Window1.xaml.cs
private void OnWindowLoaded(object
sender, EventArgs e) {
List<Book> books = new List<Book>();
books.Add(new Book("Steinbeck", "Grapes of Wrath"));
books.Add(new Book("Twain", "Huckleberry Finn"));

this.DataContext = books;
}
}

Inspecting the setup a little closer:


this.DataContext = books;

…sets up the object for all the child elements of the window to databind to – in our case, this is a
list of books.

<TextBox Text="{Binding Path=Author}"/>

Since we did not specify Source, ElementName, or RelativeSource, the TextBox will look for a
DataContext that is set somewhere either on itself or on one of its parents. It will access the
“Author” property of the currently selected Book in the list of books.

<ListBox ItemsSource="{Binding}"
IsSynchronizedWithCurrentItem="True"/>

The ItemsSource property specifies the place to populate the listbox items from. Because we
have again not specified Source, ElementName, or RelativeSource, the listbox will go looking for
a set DataContext.

IsSynchronizedWithCurrentItem is a way of saying that as the listbox selection changes,


change the current item that the binding is looking at and vice-versa. So when we keyboard
through the books in the listbox, the author in the textbox changes.

Databinding Walkthroughs
The easiest way to describe databinding is through sample code, here are several “howtos”.

Sample: Using a DataTemplate


This sample builds upon “Setting the DataContext in code”. If you notice, it’s just showing up as
“WindowsApplication14.Book”. Like Windows Form’s ListBox, it’s just calling ToString() on the
book. In Windows Forms and “Avalon” we could make Book implement ToString() or set
“DataMember” or “Path” to pick a particular property of
interest.

However, Book shouldn’t care how it’s displayed, it’s just


data – so adding too much goop onto Book is not the best
idea. In “Avalon” we can specify how the Book class should
display by using a DataTemplate.

We can add an ItemTemplate to the ListBox


<ListBox
ItemTemplate="{StaticResource BookTemplate}" ItemsSource="{Binding}"
IsSynchronizedWithCurrentItem="True">

And add a DataTemplate in our DockPanel.Resources

<DockPanel>
<DockPanel.Resources>
<DataTemplate x:Key="BookTemplate" >
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Author}"/>
<TextBlock Text=" - "/>
<TextBlock Text="{Binding Path=Title}"/>
</StackPanel>
</DataTemplate>
</DockPanel.Resources>

Foreach Book in the listbox, the DataTemplate will be evaluated. We will generate three text
blocks: one bound to the currentBook.Author property one which just shows a dash “-“ and one
which shows the currentBook.Title.

<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Author}"/>
<TextBlock Text=" - "/>
<TextBlock Text="{Binding Path=Title}"/>
</StackPanel>

Here is the full code:

<Window x:Class="WindowsApplication14.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WindowsApplication14"
Loaded="OnWindowLoaded"
>
<DockPanel>
<DockPanel.Resources>
<DataTemplate x:Key="BookTemplate" >
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Author}"/>
<TextBlock Text=" - "/>
<TextBlock Text="{Binding Path=Title}"/>
</StackPanel>
</DataTemplate>
</DockPanel.Resources>
<TextBox DockPanel.Dock="Top" Name="textBox" Text="{Binding
Path=Author}"></TextBox>
<ListBox Name="listBox" ItemTemplate="{StaticResource BookTemplate}"
ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True">
</ListBox>
</DockPanel>
</Window>

Sample: Binding to UIElement


Specifying a mnemonic on a label requires specifying the “access key” and specifying the “target”
UIElement to get focus when the mnemonic is pressed. In order to do this from XAML, you need
to use a Binding expression.

<StackPanel Orientation="Horizontal" VerticalAlignment="Top">


<Label Target="{Binding ElementName=nameTextBox}">_Name</Label>
<TextBox Name="nameTextBox"></TextBox>
</StackPanel>

- The source of the binding is specified as a UIElement by specifying the element name
- The source of the binding represents the object we want, so Path is not specified,
although we could have written this more explicitly as:
<Label
Target="{Binding ElementName=nameTextBox, Path=.}">
_Name
</Label>

Sample: Binding to a resource


This particular example is a little contrived but for the sake of simplicity, let’s assume there is a
string within the resources section the Window that you want to databind to. One textbox will
display the actual string, the other will display the length of the string.

<Window x:Class="WindowsApplication14.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WindowsApplication14"
xmlns:sys="clr-
namespace:System;assembly=System"
>
<Window.Resources>
<sys:String x:Key="someText">Some
Text</sys:String>
</Window.Resources>
<StackPanel>
<!-- Display the string -->
<TextBox
Text="{Binding Source={StaticResource someText}, Path=.}"/>

<!-- Display length of the string -->


<TextBox
Text="{Binding Source={StaticResource someText}, Path=Length}"/>
</StackPanel>
</Window>

Sample: Binding to XML file


Lets create an XML file called Books.xml

<?xml version="1.0" encoding="utf-8" ?>


<!--Books.xml-->
<BookList>
<Book>
<Title>Grapes of Wrath</Title>
<Author>Steinbeck</Author>
</Book>
<Book>
<Title>Huckleberry Finn</Title>
<Author>Twain</Author>
</Book>
</BookList>

We can then bind this to a listbox using an XmlDataProvider

<Window x:Class="WindowsApplication14.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WindowsApplication14"
xmlns:sys="clr-namespace:System;assembly=System"
>
<Window.Resources>
<XmlDataProvider x:Key="booksResource"
XPath="BookList"
Source="Books.xml">
</XmlDataProvider>
</Window.Resources>
<Grid DataContext="{StaticResource booksResource}">
<ListBox ItemsSource="{Binding XPath=Book/Author}"></ListBox>
</Grid>
</Window>

Breaking this apart a little:


<XmlDataProvider
x:Key="booksResource" ß The name of the resource
XPath="BookList" ß Where to look in the XML tree for data
Source="Books.xml" ß The URL of the XML file to load
/>

The XmlDataProvider is keyed off the name “booksResource” and using the XPath syntax (this is
an XML standard), the XmlDataProvider represents all the child elements underneath the
“<BooksList>” xml node in the file books.xml.

We can now reference the XmlDataProvider using the StaticResource markup extension, and set
our Grid’s DataContext to represent what the XmlDataProvider is returning back to us – all the
child nodes under BooksList.

<Grid DataContext="{StaticResource booksResource}">


<ListBox ItemsSource="{Binding XPath=Book/Author}"></ListBox>
</Grid>

Finally the ListBox inherits the DataContext from it’s parent Grid, but tweaks the data it wants to
display – it only wants to display the Authors – so using the XPath syntax (see Appendix B) it
further drills into the XML hierarchy to pull out all the Authors under the book nodes.

Sample: Binding to XML Data Island


If instead you wish to have the data directly in the file, you can embed it underneath the
XmlDataProvider – there is one catch: you have to put xmlns=”” in your root tag so validation will
be skipped for your data island.

<Window x:Class="WindowsApplication14.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WindowsApplication14"
>
<Window.Resources>
<XmlDataProvider
x:Key="booksResource"
XPath="Books" >
<Books xmlns="">
<Book>
<Title>Grapes of Wrath</Title>
<Author>Steinbeck</Author>
</Book>
<Book>
<Title>Huckleberry Finn</Title>
<Author>Twain</Author>
</Book>
</Books>
</XmlDataProvider>
</Window.Resources>

<Grid DataContext="{StaticResource booksResource}">


<ListBox ItemsSource="{Binding XPath=Book/Author}"></ListBox>
</Grid>
</Window>

Sample: Hierarchical Data Binding


This sample is inspired from Chris Anderson’s sample. If you want to bind to a TreeView. To
display our book data in a hierarchy, we swap the control from a ListBox to a TreeView and add
in a HierarchicalDataTemplate.

DataTemplates are a way of generating a certain set of UI to visually represent a piece of data.
In this case, we want to generate two text blocks – one representing the Value of the XML node
and one representing the Name of the XML node. The use of a hierarchical data template means
that whenever a child occurs of the same data type the template is automatically re-applied.

<Window x:Class="WindowsApplication14.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WindowsApplication14"
xmlns:sys="sys"
xmlns:sysXml="clr-namespace:System.Xml;assembly=System.Xml"
>
<Window.Resources>
<XmlDataProvider x:Key="booksResource"
XPath="Books"
Source="Books.xml">
</XmlDataProvider>
<HierarchicalDataTemplate
x:Key="booksDataTemplate"
DataType='{x:Type
sysXml:XmlNode}'
ItemsSource='{Binding
Path=ChildNodes}'>

<TextBlock Text='{Binding
Path=Value}'>
<TextBlock Text='{Binding Path=Name}' />
</TextBlock>
</HierarchicalDataTemplate>
</Window.Resources>

<Grid DataContext="{StaticResource booksResource}">


<TreeView
ItemsSource="{Binding Source={StaticResource booksResource}}"
ItemTemplate="{StaticResource booksDataTemplate}" />
</Grid>
</Window>

Advanced Databinding

CollectionView and Collection ViewSource

“Avalon” binding actually occurs via a class called CollectionView. CollectionView is an abstraction
of the DataView class in ADO.Net – it represents a view on top of a collection. CollectionView
supports Sorting, Filtering and Grouping. CollectionView also supports and tracks the “current
item” – it fills the same role as CurrencyManager in Windows Forms.

Whenever a binding to a collection is created a CollectionView for that collection is demand


created by Avalon.

CollectionViewSource is a class that enables the explicit creation of a CollectionView in


markup. It fulfills the same role as BindingSource in Windows Forms.

The next things you should learn


Obviously databinding is much more powerful and deep than could be covered here. The next
topics to explore are:

 Writing objects and classes that support databinding


o INotifyPropertyChanged
o INotifyCollectionChanged
o AttachedProperties and DependencyProperties
o ObservableCollection<T>
o BindingList<T>
 Retrieving the current item in a list using CollectionViewSource.GetDefaultView
 Sorting data in a list using CollectionViewSource.GetDefaultView(..).Sort()
 Filtering data using the CollectionViewSource.GetDefaultView(..).Filter event
 Converting data using ValueConverters
 Master/Detail databinding

WindowsForms.Net: Data binding in .Net 2.0


PDC05: PRS324: Using Data in WPF Applications
MHender: Data binding in hybrid applications
Sells: Crazy about Avalon Data Binding
MSDN: Data Binding Overview
Resources

Resources in Avalon are more than just the “classic” Win32 or Windows Forms resources such as
images, strings, and so on.

Resources can include pretty much any CLR object that can be declared in XAML – that is it must
have a default constructor and properties that are not order dependent.

Avalon objects that are declared in Resources include:

 Styles
 Brushes
 Templates
 DataSources

{StaticResource} versus {DynamicResource}

Resources can either be static (StaticResource) or dynamic (DynamicResource). Static


resources are resolved at compile time where as dynamic resources are resolved at runtime.

Use DynamicResources when: the value of the resource could change during the lifetime of the
Application.

Use StaticResources when: it’s clear that you don’t need your resource re-evaluated when
fetching it – static resources perform better than dynamic resources.

Individual resources in the Resources section require a x:Key="someKey" so that the resource
can be looked up using the {StaticResource someKey} or {DynamicResource someKey}
markup extension later.

Sample: Loading a string from a resource

<Window x:Class="WindowsApplication22.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WindowsApplication22"
xmlns:sys="clr-namespace:System;assembly=System"
>
<Window.Resources>
<sys:String x:Key="labelText">Hello World</sys:String>
</Window.Resources>
<Grid>
<Label Content="{StaticResource labelText}"/>
</Grid>
</Window>

Any FrameworkElement/FrameworkContentElement has Resources; Resources are


inherited to all children
A key idea in WPF is that resources are inherited to all children. If a Button is in a Grid within a
Window, the Button can access the resources defined in the <Grid.Resources> and the
<Window.Resources>.

There is also a notion of application-wide resources; all elements can access elements defined
within the <Application.Resources>, typically defined in the MyApp.xaml file.

Sample: Defining a Brush in a resource


The following example shows how to create an “Avalon” brush in a resources section. Note that
the brush is created in the StackPanel.Resources, so any child of the StackPanel can make use of
the resources.

<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

<StackPanel>
<StackPanel.Resources>
<SolidColorBrush x:Key="MyBrush" Color="gold"/>
</StackPanel.Resources>
<TextBlock Foreground="{StaticResource MyBrush}" Text="Text"/>
<Button Background="{StaticResource MyBrush}">Button</Button>
</StackPanel>

</Window>

Sample: Accessing resources from code


From code, it is possible to use the FindResource method to retrieve resources from the resource
dictionary.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

<StackPanel Name="stackPanel1">
<StackPanel.Resources>
<SolidColorBrush x:Key="MyBrush" Color="gold"/>
</StackPanel.Resources>
<TextBlock Name="textBlock1" Text="Text"/>
<Button Name="button1">Button</Button>
</StackPanel>
</Window>

// Window1.xaml.cs
private void OnMainWindowLoaded(object sender, EventArgs e) {
SolidColorBrush brush = stackPanel1.FindResource("MyBrush")
as SolidColorBrush;
if (brush != null) {
textBlock1.Foreground = brush;
button1.Background = brush;
}
}
Note that FindResource will surf up the element hierarchy to find the resource – this call would
have worked too:
SolidColorBrush brush = textBlock1.FindResource("MyBrush") as
SolidColorBrush;

However, calling this.FindResource (where this is the Window) will fail to find the brush, as the
brush is not defined within the Window’s resource dictionary.

Sample: Defining Application-Wide Resources


The following sample shows how to add a style to the Application.Resources resource dictionary.
In particular it adds a style for buttons; setting their background property to be aqua.

<!-- MyApp.xaml -->


<Application x:Class="CiderWindowsApplication1.MyApp"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Window1.xaml"
>
<Application.Resources>
<Style TargetType="{x:Type Button}" x:Key="AquaButton">
<Setter Property="Background" Value="Aqua"></Setter>
</Style>
</Application.Resources>
</Application>

<!-- Window1.xaml -->


<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="CiderWindowsApplication1.Window1"
Title="Main Window">

<Grid>
<!—
Searches for the “AquaButton resource
- not defined on Grid
- not defined on Window
- is defined on Application
-->
<Button Style="{StaticResource AquaButton}">I'm Aqua</Button>
</Grid>

</Window>

Resources can be stored in separate files called Resource Dictionaries


If you want to pull your styles into a separate file, this is possible by using the
MergedDictionaries property off of resources.

Sample: Using MergedDictionaries


The following sample adds a style for buttons to the entire application – keeping that style in a
separate file called ResourceDictionary.xaml

<!-- MyApp.xaml -->


<Application x:Class="CiderWindowsApplication1.MyApp"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Window1.xaml"
>
<Application.Resources>
<ResourceDictionary>
<!-- Using MergedDictionaries, we can pull in
resources from another file.
-->
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ResourceDictionary.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>

<!-- ResourceDictionary.xaml -->


<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>

<!-- Create style that sets the background aqua -->

<Style TargetType="{x:Type Button}" x:Key="AquaButton">


<Setter Property="Background" Value="Aqua"></Setter>
</Style>
</ResourceDictionary>

<!-- Window1.xaml -->

<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="CiderWindowsApplication1.Window1"
Title="Main Window">

<Grid>
<Button Style="{StaticResource AquaButton}">I'm Aqua</Button>
</Grid>
</Window>

Using System Colors and x:Static


System Brushes ( “Avalon” paints in Brushes not Colors) are not resources but a static properties
on a class called SystemColors. To fetch them (and any other static property) from XAML, we
need to use the x:Static markup extension.

<Button Background="{x:Static SystemColors.WindowBrush}">


Button
</Button>

For a full list of markup extensions, consult MSDN.


Styles, Templates and Triggers

Styles – Styles are a way of setting properties on a FrameworkElement.

Templates – Templates are a way of defining the visual structure of a control. There are really
two kinds of templates: ControlTemplates and DataTemplates

ControlTemplates – When a class derives from the Control class, it gets a Template property.
The Template property is a way of factoring out all the “visual elements” of the control so that
anyone at any time can replace the look and feel of the control. The ControlTemplate can get
back to the properties of the control through a form of databinding called TemplateBinding.

DataTemplates – These are very similar to ControlTemplates, however instead of describing


the visual representation of a control, they can describe the visual representation of any class
you can think of.

The canonical example of this is use in a listbox. In Windows Forms, you add some object – say
a “Customer” to the Items collection. The only way (without owner drawing) that the customer
can be represented is via some sort of string. In particular the customer.ToString() is called to
fetch the string to show unless the “DisplayMember” property is set.

What if you have an image for your customer or some other sort of rich data? The DataTemplate
is a way of saying “foreach customer you see, create an <image> a <textblock> for their first
name and a <textblock> for their last name.”. Now whenever anyone uses a customer object
*anywhere* in the UI, these elements will be created to visually represent the customer.

This is a way of doing Rich Data Visualization.

When should I use what?

Use Styles when what you want to do, you could achieve by just changing the external properties
of a control.

Use ControlTemplates when you want to change the visual structure of a control.

Use DataTemplates when you want to represent arbitrary data visually.

What are Triggers?

Triggers are a way of changing your templates and styles whenever either a property has
changed or an event has occurred.

Can you have more than one style apply to the same object?
No. You cannot have two styles specifying the same target type in the same Resources block. If
you have a nested panel with its own resource block the style from the local block trumps the
one from the outer block. For example:

<Window.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="Yellow"></Setter>
</Style>
</Window.Resources>
<Grid>
<Grid.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Foreground" Value="Red"></Setter>
</Style>
</Grid.Resources>
<Button >
hello world!
</Button>
</Grid>

The resultant button has a non-yellow background with red text.

This also results in an error:


<Window.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="Yellow"></Setter>
</Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Foreground" Value="Red"></Setter>
</Style>
</Window.Resources>

…as this causes a collision in the resource dictionary.

The way to achieve this is to either move the second setter line into the first style block, or if you
want two different styles use the “BasedOn” semantic. You can create a style that is “BasedOn”
another style.
<Window.Resources>
<Style x:Key="YellowButton"
TargetType="{x:Type Button}">
<Setter Property="Background" Value="Yellow"/>
</Style>
<Style x:Key="YellowButtonWithRedText"
BasedOn="{StaticResource YellowButton}"
TargetType="{x:Type Button}">
<Setter Property="Foreground" Value="Red"/>
</Style>
</Window.Resources>
<Grid>
<Button Style="{StaticResource YellowButtonWithRedText}">
Hello World!
</Button>
</Grid>

Sells/Griffiths: Programming Windows Presentation Foundation - Sample Chapter


Multithreaded Applications
WPF, like Windows Forms requires STAThread. It ensures that DispatcherObjects that you create
are accessed from the same thread that they were created on.

BackgroundWorker still works with WPF, although it has a different synchronization context to
make it work properly with WPF.

The equivalent to BeginInvoke is BeginInvoke, however this method is tucked away on the
Dispatcher.

this.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.
Normal, new EventHandler(UpdateUI));
Settings
ApplicationSettingsBase works with Avalon, ASP.Net and Windows Forms.

For more information on settings visit the FAQ. The following is the code for an options dialog:

<Window x:Class="WikiExplorer.OptionsDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WikiExplorer Options"
Width="400"
Height="160"
WindowStartupLocation="CenterOwner"
>
<Grid Name="optionsGrid" Margin="9" ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto" SharedSizeGroup="OkCancel"/>
<ColumnDefinition Width="Auto" SharedSizeGroup="OkCancel"/>
<ColumnDefinition Width="Auto" SharedSizeGroup="OkCancel"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height ="Auto"/>
<RowDefinition Height ="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.Resources>
<Style x:Key="OkCancelButtons" TargetType="{x:Type Button}">
<Setter Property="Margin" Value="3"></Setter>
<Setter Property="VerticalAlignment" Value="Bottom"></Setter>
<Setter Property="Width" Value="Auto"></Setter>
</Style>
</Grid.Resources>
<!--URL information-->
<Label VerticalAlignment="Center"
Grid.Row="0" Grid.Column="0"
TabIndex="0">_Url</Label>
<TextBox Name="urlTextBox"
Text="{Binding Path=Uri}"
Margin="3"
Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="4"
TabIndex="1"/>
<!--Local Disk Cache Information-->
<Label VerticalAlignment="Center"
Grid.Row="1" Grid.Column="0"
TabIndex="0">_Local cache</Label>
<TextBox Name="localDiskCacheLocationTextBox"
Text="{Binding Path=LocalCacheLocation}"
Margin="3,3,40,3"
Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="4"
TabIndex="1"/>
<Button Name="Browse"
Click="OnLocalDiskCacheBrowseClicked"
Grid.Row="1" Grid.Column="4"
VerticalAlignment="Center" HorizontalAlignment="Right"
Width="40">...</Button>
<!--OK/Cancel/Restore-->
<Button Name="OkButton"
Click="OnOkClicked"
IsDefault="True"
Style="{StaticResource OkCancelButtons}"
Grid.Row="2" Grid.Column="2">_Ok</Button>
<Button Name="restoreDefaultSettings"
Click="OnRestoreClicked"
Style="{StaticResource OkCancelButtons}"
Grid.Row="2" Grid.Column="3">_Restore Defaults</Button>
<Button Name="CancelButton"
IsCancel="True"
Style="{StaticResource OkCancelButtons}"
Grid.Row="2" Grid.Column="4">_Cancel</Button>
</Grid>
</Window>

public partial class OptionsDialog : Window {


WikiExplorerOptions explorerOptions;

public OptionsDialog() {
InitializeComponent();
explorerOptions = new WikiExplorerOptions();
this.DataContext = explorerOptions;
this.Background = SystemColors.ControlBrush;
}

void OnOkClicked(object sender, System.EventArgs e) {


if (explorerOptions != null) {
explorerOptions.Save();
}
this.Close();
}
void OnRestoreClicked(object sender, System.EventArgs e) {
if (explorerOptions != null) {
explorerOptions.Reset();
}
}
void OnLocalDiskCacheBrowseClicked(object sender,
System.EventArgs e) {
OpenFileDialog ofd = new OpenFileDialog();
if (ofd.ShowDialog() == true) {
explorerOptions.LocalCacheLocation =
System.IO.Path.GetDirectoryName(ofd.FileName);
}

class WikiExplorerOptions : ApplicationSettingsBase {

[UserScopedSetting]
[DefaultSettingValue("http://www.flexwiki.com/")]
public string Uri {
get {
return this["Uri"] as string;
}
set {
this["Uri"]=value;
}
}

[UserScopedSetting]
[DefaultSettingValue("")]
public string LocalCacheLocation {
get {
string localCache = this["LocalCacheLocation"] as
string;
if (string.IsNullOrEmpty(localCache)) {
localCache =
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalAp
plicationData), "WikiExplorer");
}
return localCache;
}
set {
this["LocalCacheLocation"] = value;
}
}

public string LocalCacheDirectory {

get {
Uri uri = new Uri(this.Uri);

return Path.Combine(LocalCacheLocation, uri.Host);


}
}

}
}

Common questions

Powered by AI

In Avalon, StackPanel and FlowLayoutPanel have distinct behaviors regarding stretching and alignment. StackPanel uses the Orientation property to specify vertical or horizontal flow and automatically stretches items, similar to the DockPanel, unless constraints like Width, Height, HorizontalAlignment, or VerticalAlignment are applied. In contrast, FlowLayoutPanel does not inherently stretch items across its panel. This makes StackPanel preferable for situations requiring uniform spacing and alignment control .

In Avalon, RoutedEvents are used to process input at multiple levels and support both 'tunneling' and 'bubbling' event types. Tunneling events, which start at the topmost element and work their way down to the target element, allow ancestors to preview events before they reach the target. Bubbling events, on the other hand, start at the element that raised the event and propagate up the parent chain. This dual structure provides flexible event handling, allowing for comprehensive input management akin to DHTML event models .

Avalon handles input preprocessing similarly to Windows Forms by needing to manage mouse, keyboard, and other inputs. Specific to Avalon is the incorporation of routed events, which include tunneled 'Preview' events allowing parents to process inputs before children, and bubbled 'result' events to manage responses. Commanding is another feature, offering an alternative event handling mechanism that abstracts command logic from UI event handling, reducing coupling and increasing flexibility .

The 'LastChildFill' property in the DockPanel of Avalon is critical for determining how the last added child fills available space. By default, it is set to true, causing the last child to fill any remaining space comprehensively, mimicking a fill behavior. To align with traditional docking styles where no element inherently fills remaining space, 'LastChildFill' can be set to false. This introduces explicit size and alignment control for each child, akin to traditional DockStyle configurations in Windows Forms .

In Avalon, the HierarchicalDataTemplate enhances TreeView controls by enabling dynamic generation of UI elements based on data hierarchies. When displaying XML data, a HierarchicalDataTemplate specifies how each node and its children should be represented visually, applying the template automatically for child nodes of the same type. This allows developers to define once how XML nodes are displayed and leverage automatic reapplication of these templates as children are processed .

In Avalon, setting the DataContext provides a default data source for elements and their descendants, facilitating straightforward binding. If a different source is needed, explicit alternatives include using the Source property to override the inherited DataContext, the ElementName property for element-to-element binding, or the RelativeSource property for binding within templates or to ancestors .

CollectionView in Avalon functions as an abstraction over collections, enabling advanced data manipulation through sorting, filtering, and grouping. It acts as a view layer similar to ADO.Net's DataView, providing synchronization with the 'current item' and managing the state of data in bindings. By supporting interfaces like INotifyPropertyChanged and attached properties, CollectionView facilitates powerful, responsive interfaces in data-driven applications .

The primary advantage of using Grid over TableLayoutPanel in Avalon is its flexibility for dynamic layout adjustments. The Grid can hold more than one control within a cell, making it possible to use complex layouts. In Avalon, the Grid's ability to specify absolute positioning with the Margin property allows developers to fine-tune control placements, while RowDefinition and ColumnDefinition facilitate both fixed and dynamic sizing by accommodating Absolute, Auto, and Percent-based measurements .

The Canvas control in Avalon allows positioning by using fixed pixel coordinates through attached properties like Canvas.Top and Canvas.Left. It differs from other controls because specifying Canvas.Right and Canvas.Bottom does not change the size of the item. This means the Canvas is used primarily for absolute positioning rather than dynamic resizing or alignment, making it distinct compared to more flexible controls such as the Grid, which accommodates growth, shrinkage, and shifting of adjacent controls .

In Avalon, specifying the 'Margin' property allows for absolute positioning within a Grid cell by defining the space outside a control, essentially moving it inward from the cell’s edges by the specified amounts. By using margins, developers can precisely position controls within cells without affecting the overall flow of the Grid layout, maintaining both the flexibility of resizable parents and the precision typical of absolute positioning methods .

You might also like