Index of Locally Available Projects:: Ebook
Index of Locally Available Projects:: Ebook
Index of Locally Available Projects:: Ebook
© 2008 Xavier Roche & other contributors - Web Design: Leto Kauler.
Home Contact Us
Download as PDF
The complete WPF tutorial
Download this entire
tutorial as PDF right
now!
Welcome to this WPF tutorial, currently consisting of 93 articles, where you'll About WPF
learn to make your own applications using the WPF UI framework. If you're
What is WPF?
brand new to WPF, then we recommend that you start from the first chapter
WPF vs. WinForms
and then read your way through all of it.
Have a look at the Table of contents to the right, where all the chapters are
listed and be sure to come back regularly, as we will keep adding new Getting started
chapters to it. We hope that this tutorial will get you started properly on WPF. Visual Studio Express
Hello, WPF!
Everything here is free, and we hope you like our work. If you do, then all we
ask is that you link to this tutorial on your website, Facebook profile, personal
blog or anything else where a link is possible. Also, if you see anything
XAML
interesting in one of our ad blocks, please click it to help us maintain this
tutorial. Thank you! What is XAML?
Basic XAML
A basic knowledge of C# is recommended when learning to use WPF. If you Events in XAML
don't already know some C#, you may wish to get a better sense of by going
through a C# tutorial.
A WPF application
Introduction
>> Start the tutorial
The Window
Working with App.xaml
Command-line parameters
Resources
Handling exceptions
Next
Basic controls
The TextBlock control
comments powered by Disqus
The TextBlock control - Inline
formatting
The Label control
The TextBox control
The CheckBox control
Panels
Introduction to WPF Panels
The Canvas
The WrapPanel
The StackPanel
The DockPanel
The Grid
The Grid - Rows & Columns
The Grid - Units
The Grid - Spanning
The Grid - GridSplitter
Using the Grid: A contact
form
Data binding
Introduction
Hello, bound world!
Using the DataContext
The UpdateSourceTrigger
property
Responding to changes
Value conversion with
IValueConverter
The StringFormat property
Debugging data bindings
Commands
Introduction
Using commands
Implementing custom
commands
Common interface
controls
The Menu control
The ContextMenu
The ToolBar control
The StatusBar control
The Ribbon Control
Introduction
The
FlowDocumentScrollViewer
control
The
FlowDocumentPageViewer
control
The FlowDocumentReader
control
Creating a FlowDocument
from Code-behind
Advanced FlowDocument
content
The RichTextBox control
Misc. controls
The Border control
The Slider control
The ProgressBar control
The WebBrowser control
The WindowsFormsHost
control
The TabControl
Using the TabControl
Tab positions
Styling the TabItems
List controls
The ItemsControl
The ListBox control
The ComboBox control
ListView filtering
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
The complete WPF tutorial
Download this entire
tutorial as PDF right
now!
Welcome to this WPF tutorial, currently consisting of 93 articles, where you'll About WPF
learn to make your own applications using the WPF UI framework. If you're
What is WPF?
brand new to WPF, then we recommend that you start from the first chapter
WPF vs. WinForms
and then read your way through all of it.
Have a look at the Table of contents to the right, where all the chapters are
listed and be sure to come back regularly, as we will keep adding new Getting started
chapters to it. We hope that this tutorial will get you started properly on WPF. Visual Studio Express
Hello, WPF!
Everything here is free, and we hope you like our work. If you do, then all we
ask is that you link to this tutorial on your website, Facebook profile, personal
blog or anything else where a link is possible. Also, if you see anything
XAML
interesting in one of our ad blocks, please click it to help us maintain this
tutorial. Thank you! What is XAML?
Basic XAML
A basic knowledge of C# is recommended when learning to use WPF. If you Events in XAML
don't already know some C#, you may wish to get a better sense of by going
through a C# tutorial.
A WPF application
Introduction
>> Start the tutorial
The Window
Working with App.xaml
Command-line parameters
Resources
Handling exceptions
Next
Basic controls
The TextBlock control
comments powered by Disqus
The TextBlock control - Inline
formatting
The Label control
The TextBox control
The CheckBox control
Panels
Introduction to WPF Panels
The Canvas
The WrapPanel
The StackPanel
The DockPanel
The Grid
The Grid - Rows & Columns
The Grid - Units
The Grid - Spanning
The Grid - GridSplitter
Using the Grid: A contact
form
Data binding
Introduction
Hello, bound world!
Using the DataContext
The UpdateSourceTrigger
property
Responding to changes
Value conversion with
IValueConverter
The StringFormat property
Debugging data bindings
Commands
Introduction
Using commands
Implementing custom
commands
Common interface
controls
The Menu control
The ContextMenu
The ToolBar control
The StatusBar control
The Ribbon Control
Introduction
The
FlowDocumentScrollViewer
control
The
FlowDocumentPageViewer
control
The FlowDocumentReader
control
Creating a FlowDocument
from Code-behind
Advanced FlowDocument
content
The RichTextBox control
Misc. controls
The Border control
The Slider control
The ProgressBar control
The WebBrowser control
The WindowsFormsHost
control
The TabControl
Using the TabControl
Tab positions
Styling the TabItems
List controls
The ItemsControl
The ListBox control
The ComboBox control
ListView filtering
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
WPF vs. WinForms
Download this entire
tutorial as PDF right
now!
In the previous chapter, we talked about what WPF is and a little bit about About WPF
WinForms. In this chapter, I will try to compare the two, because while they
What is WPF?
do serve the same purpose, there is a LOT of differences between them. If
WPF vs. WinForms
you have never worked with WinForms before, and especially if WPF is your
very first GUI framework, you may skip this chapter, but if you're interested in
the differences then read on.
Getting started
The single most important difference between WinForms and WPF is the fact Visual Studio Express
that while WinForms is simply a layer on top of the standard Windows Hello, WPF!
controls (e.g. a TextBox), WPF is built from scratch and doesn't rely on
standard Windows controls in almost all situations. This might seem like a
subtle difference, but it really isn't, which you will definitely notice if you have
XAML
ever worked with a framework that depends on Win32/WinAPI.
What is XAML?
A great example of this is a button with an image and text on it. This is not a Basic XAML
standard Windows control, so WinForms doesn't offer you this possibility out Events in XAML
of the box. Instead you will have to draw the image yourself, implement your
own button that supports images or use a 3rd party control. With WPF, a
button can contain anything because it's essentially a border with content A WPF application
and various states (e.g. untouched, hovered, pressed). The WPF button is Introduction
"look-less", as are most other WPF controls, which means that it can contain The Window
a range of other controls inside of it. You want a button with an image and Working with App.xaml
some text? Just put an Image and a TextBlock control inside of the button Command-line parameters
and you're done! You simply don’t get this kind of flexibility out of the Resources
standard WinForms controls, which is why there's a big market for rather Handling exceptions
simple implementations of controls like buttons with images and so on.
The drawback to this flexibility is that sometimes you will have to work harder
to achieve something that was very easy with WinForms, because it was
Basic controls
created for just the scenario you need it for. At least that's how it feels in the The TextBlock control
beginning, where you find yourself creating templates to make a ListView The TextBlock control - Inline
with an image and some nicely aligned text, something that the WinForms formatting
ListViewItem does in a single line of code. The Label control
The TextBox control
This was just one difference, but as you work with WPF, you will realize that it The CheckBox control
is in fact the underlying reason for many of the other differences - WPF is The RadioButton control
simply just doing things in its own way, for better and for worse. You're no The PasswordBox control
longer constrained to doing things the Windows way, but to get this kind of
flexibility, you pay with a little more work when you're really just looking to do
things the Windows way. Panels
The following is a completely subjective list of the key advantages for WPF Introduction to WPF Panels
and WinForms. It should give you a better idea of what you're going into. The Canvas
The WrapPanel
WPF advantages The StackPanel
The DockPanel
It's newer and thereby more in tune with current standards The Grid
Microsoft is using it for a lot of new applications, e.g. Visual Studio The Grid - Rows & Columns
It's more flexible, so you can do more things without having to write or The Grid - Units
buy new controls The Grid - Spanning
When you do need to use 3rd party controls, the developers of these The Grid - GridSplitter
controls will likely be more focused on WPF because it's newer Using the Grid: A contact
XAML makes it easy to create and edit your GUI, and allows the work form
to be split between a designer (XAML) and a programmer (C#,
VB.NET etc.)
Databinding, which allows you to get a more clean separation of data
Data binding
and layout
Introduction
Uses hardware acceleration for drawing the GUI, for better
Hello, bound world!
performance
Using the DataContext
It allows you to make user interfaces for both Windows applications
The UpdateSourceTrigger
and web applications (Silverlight/XBAP)
property
WinForms advantages Responding to changes
Value conversion with
It's older and thereby more tried and tested IValueConverter
There are already a lot of 3rd party controls that you can buy or get for The StringFormat property
free Debugging data bindings
The designer in Visual Studio is still, as of writing, better for WinForms
than for WPF, where you will have to do more of the work yourself
with WPF Commands
Introduction
Previous Next Using commands
Implementing custom
commands
Introduction
The
FlowDocumentScrollViewer
control
The
FlowDocumentPageViewer
control
The FlowDocumentReader
control
Creating a FlowDocument
from Code-behind
Advanced FlowDocument
content
The RichTextBox control
Misc. controls
The Border control
The Slider control
The ProgressBar control
The WebBrowser control
The WindowsFormsHost
control
The TabControl
Using the TabControl
Tab positions
Styling the TabItems
List controls
The ItemsControl
The ListBox control
The ComboBox control
ListView filtering
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
What is WPF?
Download this entire
tutorial as PDF right
now!
WPF, which stands for Windows Presentation Foundation, is Microsoft's latest About WPF
approach to a GUI framework, used with the .NET framework.
What is WPF?
But what IS a GUI framework? GUI stands for Graphical User Interface, and WPF vs. WinForms
you're probably looking at one right now. Windows has a GUI for working
with your computer, and the browser that you're likely reading this document
in has a GUI that allows you to surf the web. Getting started
Visual Studio Express
A GUI framework allows you to create an application with a wide range of GUI
Hello, WPF!
elements, like labels, textboxes and other well known elements. Without a
GUI framework you would have to draw these elements manually and handle
all of the user interaction scenarios like text and mouse input. This is a LOT
XAML
of work, so instead, most developers will use a GUI framework which will do
all the basic work and allow the developers to focus on making great What is XAML?
applications. Basic XAML
Events in XAML
There are a lot of GUI frameworks out there, but for .NET developers, the
most interesting ones are currently WinForms and WPF. WPF is the newest,
but Microsoft is still maintaining and supporting WinForms. As you will see in A WPF application
the next chapter, there are quite a few differences between the two
Introduction
frameworks, but their purpose is the same: To make it easy to create
The Window
applications with a great GUI.
Working with App.xaml
In the next chapter, we will look at the differences between WinForms and Command-line parameters
WPF. Resources
Handling exceptions
Next
Basic controls
The TextBlock control
comments powered by Disqus
The TextBlock control - Inline
formatting
The Label control
The TextBox control
The CheckBox control
Panels
Introduction to WPF Panels
The Canvas
The WrapPanel
The StackPanel
The DockPanel
The Grid
The Grid - Rows & Columns
The Grid - Units
The Grid - Spanning
The Grid - GridSplitter
Using the Grid: A contact
form
Data binding
Introduction
Hello, bound world!
Using the DataContext
The UpdateSourceTrigger
property
Responding to changes
Value conversion with
IValueConverter
The StringFormat property
Debugging data bindings
Commands
Introduction
Using commands
Implementing custom
commands
Common interface
controls
The Menu control
The ContextMenu
The ToolBar control
The StatusBar control
The Ribbon Control
Introduction
The
FlowDocumentScrollViewer
control
The
FlowDocumentPageViewer
control
The FlowDocumentReader
control
Creating a FlowDocument
from Code-behind
Advanced FlowDocument
content
The RichTextBox control
Misc. controls
The Border control
The Slider control
The ProgressBar control
The WebBrowser control
The WindowsFormsHost
control
The TabControl
Using the TabControl
Tab positions
Styling the TabItems
List controls
The ItemsControl
The ListBox control
The ComboBox control
ListView filtering
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
Visual Studio Express
Download this entire
tutorial as PDF right
now!
WPF is, as already described, a combination of XAML (markup) and About WPF
C#/VB.NET/any other .NET language. All of it can be edited in any text
What is WPF?
editor, even Notepad included in Windows, and then compiled from the
WPF vs. WinForms
command line. However, most developers prefer to use an IDE (Integrated
Development Environment), since it makes everything, from writing code to
designing the interface and compiling it all so much easier.
Getting started
The preferred choice for a .NET/WPF IDE is Visual Studio, which costs a lot Visual Studio Express
quite a bit of money though. Luckily, Microsoft has decided to make it easy Hello, WPF!
and absolutely free for everyone to get started with .NET and WPF, so they
have created a free version of Visual Studio, called Visual Studio Express.
This version contains less functionality than the real Visual Studio, but it has
XAML
everything that you need to get started learning WPF and make real
What is XAML?
applications.
Basic XAML
The latest version, as of writing this text, is Microsoft Visual Studio Express Events in XAML
2012. To create WPF applications, you should get the Windows Desktop
edition, which can be downloaded for free from this website:
http://www.microsoft.com/visualstudio/eng/products/visual-studio-express-for- A WPF application
windows-desktop. Introduction
The Window
After downloading and installing, you can use this product for 30 days without
Working with App.xaml
any registration. After that, you will need to register it on the above
Command-line parameters
mentioned website, which is also completely free.
Resources
Handling exceptions
Previous Next
Basic controls
comments powered by Disqus
The TextBlock control
The TextBlock control - Inline
formatting
The Label control
The TextBox control
The CheckBox control
Panels
Introduction to WPF Panels
The Canvas
The WrapPanel
The StackPanel
The DockPanel
The Grid
The Grid - Rows & Columns
The Grid - Units
The Grid - Spanning
The Grid - GridSplitter
Using the Grid: A contact
form
Data binding
Introduction
Hello, bound world!
Using the DataContext
The UpdateSourceTrigger
property
Responding to changes
Value conversion with
IValueConverter
The StringFormat property
Debugging data bindings
Commands
Introduction
Using commands
Implementing custom
commands
Common interface
controls
The Menu control
The ContextMenu
The ToolBar control
The StatusBar control
The Ribbon Control
Introduction
The
FlowDocumentScrollViewer
control
The
FlowDocumentPageViewer
control
The FlowDocumentReader
control
Creating a FlowDocument
from Code-behind
Advanced FlowDocument
content
The RichTextBox control
Misc. controls
The Border control
The Slider control
The ProgressBar control
The WebBrowser control
The WindowsFormsHost
control
The TabControl
Using the TabControl
Tab positions
Styling the TabItems
List controls
The ItemsControl
The ListBox control
The ComboBox control
ListView filtering
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
Hello, WPF!
Download this entire
tutorial as PDF right
now!
The first and very classic example in pretty much any programming tutorial is About WPF
the "Hello, world!" example, but in this tutorial we'll go nuts and change that
What is WPF?
into "Hello, WPF!" instead. The goal is simply to get this piece of text onto the
WPF vs. WinForms
screen, to show you how easy it is to get started.
The rest of this tutorial assumes that you have an IDE installed, preferably
Visual Studio or Visual Studio Express (see the previous article for Getting started
instructions on how to get it). If you're using another product, you will have to Visual Studio Express
adapt the instructions to your product. Hello, WPF!
In Visual Studio, start by selecting New project from the File menu. On the
left, you should have a tree of categories. This tutorial will focus on C#
XAML
whenever code is involved, so you should select that from the list of
templates, and since we'll be creating Windows applications, you should What is XAML?
select Windows from the tree. This will give you a list of possible Windows Basic XAML
application types to the right, where you should select a WPF Application. I Events in XAML
named my project "HelloWPF" in the Name text field. Make sure that the rest
of the settings in the bottom part of the dialog are okay and then press the
Ok button. A WPF application
Introduction
Your new project will have a couple of files, but we will focus on just one of
The Window
them now: MainWindox.xaml. This is the applications primary window, the
Working with App.xaml
one shown first when launching the application, unless you specifically
Command-line parameters
change this. The XAML code found in it (XAML is discussed in details in
Resources
another chapter of this tutorial) should look something like this:
Handling exceptions
<Window x:Class="WpfApplication1.MainWindow"
Basic controls
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
The TextBlock control
The TextBlock control - Inline
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" formatting
Title="MainWindow" Height="350" Width="525"> The Label control
<Grid> The TextBox control
The CheckBox control
This is the base XAML that Visual Studio creates for our window, all parts of it
Panels
explained in the chapters on XAML and "The Window". You can actually run Introduction to WPF Panels
the application now (select Debug -> Start debugging or press F5) to see the The Canvas
empty window that our application currently consists of, but now it's time to The WrapPanel
get our message on the screen. We'll do it by adding a TextBlock control to The StackPanel
the Grid panel, with our aforementioned message as the content: The DockPanel
The Grid
<Window x:Class="WpfApplication1.MainWindow" The Grid - Rows & Columns
The Grid - Units
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta The Grid - Spanning
The Grid - GridSplitter
Using the Grid: A contact
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" form
Title="MainWindow" Height="350" Width="525">
<Grid>
<TextBlock HorizontalAlignment="Center" Data binding
VerticalAlignment="Center" FontSize="72"> Introduction
Hello, WPF! Hello, bound world!
</TextBlock> Using the DataContext
</Grid> The UpdateSourceTrigger
</Window> property
Responding to changes
Value conversion with
Try running the application now (select Debug -> Start debugging or press IValueConverter
F5) and see the beautiful result of your hard work - your first WPF The StringFormat property
application: Debugging data bindings
Commands
Introduction
Using commands
Implementing custom
commands
Common interface
controls
The Menu control
The ContextMenu
The ToolBar control
The StatusBar control
The Ribbon Control
You will notice that we used three different attributes on the TextBlock to get a
custom alignment (in the middle of the window), as well the FontSize
Rich Text controls
property to get bigger text. All of these concepts will be treated in later
articles. Introduction
The
Congratulations on making it this far. Now go read the rest of the tutorial and FlowDocumentScrollViewer
soon you will master WPF! control
The
Previous Next FlowDocumentPageViewer
control
The FlowDocumentReader
control
Creating a FlowDocument
comments powered by Disqus
from Code-behind
Advanced FlowDocument
content
The RichTextBox control
Misc. controls
The Border control
The Slider control
The ProgressBar control
The WebBrowser control
The WindowsFormsHost
control
The TabControl
Using the TabControl
Tab positions
Styling the TabItems
List controls
The ItemsControl
The ListBox control
The ComboBox control
ListView filtering
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
What is XAML?
Download this entire
tutorial as PDF right
now!
XAML, which stands for eXtensible Application Markup Language, is About WPF
Microsoft's variant of XML for describing a GUI. In previous GUI frameworks,
What is WPF?
like WinForms, a GUI was created in the same language that you would use
WPF vs. WinForms
for interacting with the GUI, e.g. C# or VB.NET and usually maintained by the
designer (e.g. Visual Studio), but with XAML, Microsoft is going another way.
Much like with HTML, you are able to easily write and edit your GUI.
Getting started
This is not really a XAML tutorial, but I will briefly tell you about how you use Visual Studio Express
it, because it's such an essential part of WPF. Whether you're creating a Hello, WPF!
Window or a Page, it will consist of a XAML document and a CodeBehind
file, which together creates the Window/Page. The XAML file describes the
interface with all its elements, while the CodeBehind handles all the events
XAML
and has access to manipulate with the XAML controls.
What is XAML?
In the next chapters, we will have a look at how XAML works and how you Basic XAML
use it to create your interface. Events in XAML
Previous Next
A WPF application
Introduction
comments powered by Disqus The Window
Working with App.xaml
Command-line parameters
Resources
Handling exceptions
Basic controls
The TextBlock control
The TextBlock control - Inline
formatting
The Label control
The TextBox control
The CheckBox control
Panels
Introduction to WPF Panels
The Canvas
The WrapPanel
The StackPanel
The DockPanel
The Grid
The Grid - Rows & Columns
The Grid - Units
The Grid - Spanning
The Grid - GridSplitter
Using the Grid: A contact
form
Data binding
Introduction
Hello, bound world!
Using the DataContext
The UpdateSourceTrigger
property
Responding to changes
Value conversion with
IValueConverter
The StringFormat property
Debugging data bindings
Commands
Introduction
Using commands
Implementing custom
commands
Common interface
controls
The Menu control
The ContextMenu
The ToolBar control
The StatusBar control
The Ribbon Control
Introduction
The
FlowDocumentScrollViewer
control
The
FlowDocumentPageViewer
control
The FlowDocumentReader
control
Creating a FlowDocument
from Code-behind
Advanced FlowDocument
content
The RichTextBox control
Misc. controls
The Border control
The Slider control
The ProgressBar control
The WebBrowser control
The WindowsFormsHost
control
The TabControl
Using the TabControl
Tab positions
Styling the TabItems
List controls
The ItemsControl
The ListBox control
The ComboBox control
ListView filtering
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
Basic XAML
Download this entire
tutorial as PDF right
now!
In the previous chapter, we talked about what XAML is and what you use it About WPF
for, but how do you create a control in XAML? As you will see from the next
What is WPF?
example, creating a control in XAML is as easy as writing it's name,
WPF vs. WinForms
surrounded by angle brackets. For instance, a Button looks like this:
<Button>
Getting started
Visual Studio Express
XAML tags has to be ended, either by writing the end tag or by putting a
Hello, WPF!
forward slash at the end of the start tag:
<Button></Button>
XAML
What is XAML?
Or
Basic XAML
Events in XAML
<Button />
A lot of controls allow you to put content between the start and end tags, A WPF application
which is then the content of the control. For instance, the Button control Introduction
allows you to specify the text shown on it between the start and end tags: The Window
Working with App.xaml
<Button>A button</Button> Command-line parameters
Resources
HTML is not case-sensitive, but XAML is, because the control name has to Handling exceptions
correspond to a type in the .NET framework. The same goes for attribute
names, which corresponds to the properties of the control. Here's a button
where we define a couple of properties by adding attributes to the tag: Basic controls
The TextBlock control
<Button FontWeight="Bold" Content="A button" /> The TextBlock control - Inline
formatting
The Label control
We set the FontWeight property, giving us bold text, and then we set the
The TextBox control
Content property, which is the same as writing the text between the start and
The CheckBox control
end tag. However, all attributes of a control may also be defined like this,
<Button>
Panels
<Button.FontWeight>Bold</Button.FontWeight>
<Button.Content>A button</Button.Content> Introduction to WPF Panels
</Button> The Canvas
The WrapPanel
The StackPanel
The result is exactly the same as above, so in this case, it's all about syntax
The DockPanel
and nothing else. However, a lot of controls allow content other than text, for
The Grid
instance other controls. Here's an example where we have text in different
The Grid - Rows & Columns
colors on the same button by using several TextBlock controls inside of the
The Grid - Units
Button:
The Grid - Spanning
The Grid - GridSplitter
<Button> Using the Grid: A contact
<Button.FontWeight>Bold</Button.FontWeight>
form
<Button.Content>
<WrapPanel>
<TextBlock Foreground="Blue">Multi</TextBlock>
Data binding
<TextBlock Foreground="Red">Color</TextBlock>
<TextBlock>Button</TextBlock> Introduction
</WrapPanel> Hello, bound world!
</Button.Content> Using the DataContext
</Button> The UpdateSourceTrigger
property
Responding to changes
The Content property only allows for a single child element, so we use a
Value conversion with
WrapPanel to contain the differently colored blocks of text. Panels, like the
IValueConverter
WrapPanel, plays an important role in WPF and we will discuss them in much
The StringFormat property
more details later on - for now, just consider them as containers for other
Debugging data bindings
controls. The exact same result can be accomplished with the following
markup, which is simply another way of writing the same:
Commands
<Button FontWeight="Bold">
Introduction
<WrapPanel>
Using commands
<TextBlock Foreground="Blue">Multi</TextBlock>
Implementing custom
<TextBlock Foreground="Red">Color</TextBlock>
commands
<TextBlock>Button</TextBlock>
</WrapPanel>
</Button>
Common interface
controls
Code vs. XAML
The Menu control
Hopefully the above examples show you that XAML is pretty easy to write, but The ContextMenu
with a lot of different ways of doing it, and if you think that the above example The ToolBar control
is a lot of markup to get a button with text in different colors, then try The StatusBar control
comparing it to doing the exact same thing in C#: The Ribbon Control
Introduction
WrapPanel pnl = new WrapPanel(); The
FlowDocumentScrollViewer
TextBlock txt = new TextBlock(); control
txt.Text = "Multi"; The
txt.Foreground = Brushes.Blue; FlowDocumentPageViewer
pnl.Children.Add(txt); control
The FlowDocumentReader
txt = new TextBlock(); control
txt.Text = "Color"; Creating a FlowDocument
txt.Foreground = Brushes.Red; from Code-behind
pnl.Children.Add(txt); Advanced FlowDocument
content
txt = new TextBlock(); The RichTextBox control
txt.Text = "Button";
pnl.Children.Add(txt);
Misc. controls
btn.Content = pnl;
The Border control
pnlMain.Children.Add(btn);
The Slider control
The ProgressBar control
Of course the above example could be written less explicitly and using more The WebBrowser control
syntactical sugar, but I think the point still stands: XAML is pretty short and The WindowsFormsHost
concise for describing interfaces. control
Previous Next
The TabControl
Using the TabControl
Tab positions
comments powered by Disqus Styling the TabItems
List controls
The ItemsControl
The ListBox control
The ComboBox control
ListView filtering
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
Events in XAML
Download this entire
tutorial as PDF right
now!
Most modern UI frameworks are event driven and so is WPF. All of the About WPF
controls, including the Window (which also inherits the Control class)
What is WPF?
exposes a range of events that you may subscribe to. You can subscribe to
WPF vs. WinForms
these events, which means that your application will be notified when they
occur and you may react to that.
There are many types of events, but some of the most commonly used are Getting started
there to respond to the user's interaction with your application using the Visual Studio Express
mouse or the keyboard. On most controls you will find events like KeyDown, Hello, WPF!
KeyUp, MouseDown, MouseEnter, MouseLeave, MouseUp and several
others.
XAML
We will look more closely at how events work in WPF, since this is a complex
topic, but for now, you need to know how to link a control event in XAML to a What is XAML?
piece of code in your Code-behind file. Have a look at this example: Basic XAML
Events in XAML
<Window x:Class="WpfTutorialSamples.XAML.EventsSample"
</Grid> Basic controls
</Window>
The TextBlock control
The TextBlock control - Inline
formatting
Notice how we have subscribed to the MouseUp event of the Grid by writing a The Label control
method name. This method needs to be defined in code-behind, using the The TextBox control
correct event signature. In this case it should look like this: The CheckBox control
Fortunately, Visual Studio can help us to generate a correct event handler for Data binding
an event. The easiest way to do this is to simply write the name of the event Introduction
in XAML and then let the IntelliSense of VS do the rest for you: Hello, bound world!
Using the DataContext
The UpdateSourceTrigger
property
Responding to changes
Value conversion with
IValueConverter
When you select <New Event Handler> Visual Studio will generate an The StringFormat property
appropriate event handler in your Code-behind file. It will be named <control Debugging data bindings
name>_<event name>, in our case pnlMainGrid_MouseDown. Right-click
in the event name and select Navigate to Event Handler and VS will take
you right to it. Commands
Introduction
Subscribing to an event from Code-behind Using commands
Implementing custom
The most common way to subscribe to events is explained above, but there
commands
may be times where you want to subscribe to the event directly from Code-
behind instead. This is done using the += C# syntax, where you add an event
handler to event directly on the object. The full explanation of this belongs in
a dedicated C# example, but for comparison, here's an example: Common interface
controls
using System; The Menu control
using System.Windows; The ContextMenu
using System.Windows.Input; The ToolBar control
The StatusBar control
The Ribbon Control
namespace WpfTutorialSamples.XAML
{
public partial class EventsSample : Window Rich Text controls
{ Introduction
public EventsSample() The
{ FlowDocumentScrollViewer
InitializeComponent(); control
pnlMainGrid.MouseUp += new The
MouseButtonEventHandler(pnlMainGrid_MouseUp); FlowDocumentPageViewer
} control
The FlowDocumentReader
private void pnlMainGrid_MouseUp(object control
sender, MouseButtonEventArgs e) Creating a FlowDocument
{ from Code-behind
MessageBox.Show("You clicked me at Advanced FlowDocument
" + e.GetPosition(this).ToString()); content
} The RichTextBox control
}
}
Misc. controls
The Border control
Once again, you need to know which delegate to use, and once again, Visual The Slider control
Studio can help you with this. As soon as you write: The ProgressBar control
The WebBrowser control
pnlMainGrid.MouseDown +=
The WindowsFormsHost
Visual Studio will offer its assistance: control
The TabControl
Using the TabControl
Tab positions
Simply press the [Tab] key twice to have Visual Studio generate the correct Styling the TabItems
event handler for you, right below the current method, ready for
imeplentation. When you subscribe to the events like this, you don't need to
do it in XAML. List controls
The ItemsControl
Previous Next The ListBox control
The ComboBox control
ListView filtering
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
A WPF Application - Introduction
Download this entire
tutorial as PDF right
now!
In this tutorial, our primary focus will be on using WPF to create applications. About WPF
As you may know, .NET can be executed on all platforms which have a .NET
What is WPF?
implementation, but the most common platform is still Microsoft Windows.
WPF vs. WinForms
When we talk about Windows applications in this tutorial, it really just means
an application that runs on Windows (or another .NET compatible platform)
and not in a browser or remotely over the Internet.
Getting started
A WPF application requires the .NET framework to run, just like any other Visual Studio Express
.NET application type. Fortunately, Microsoft has been including the .NET Hello, WPF!
framework on all versions of Windows since Vista, and they have been
pushing out the framework on older versions through Windows Update. In
other words, you can be pretty sure that most Windows users out there will
XAML
be able to run your WPF application.
What is XAML?
In the following chapters we will have a look at the structure and various Basic XAML
aspects of a WPF application. Events in XAML
Previous Next
A WPF application
Introduction
comments powered by Disqus The Window
Working with App.xaml
Command-line parameters
Resources
Handling exceptions
Basic controls
The TextBlock control
The TextBlock control - Inline
formatting
The Label control
The TextBox control
The CheckBox control
Panels
Introduction to WPF Panels
The Canvas
The WrapPanel
The StackPanel
The DockPanel
The Grid
The Grid - Rows & Columns
The Grid - Units
The Grid - Spanning
The Grid - GridSplitter
Using the Grid: A contact
form
Data binding
Introduction
Hello, bound world!
Using the DataContext
The UpdateSourceTrigger
property
Responding to changes
Value conversion with
IValueConverter
The StringFormat property
Debugging data bindings
Commands
Introduction
Using commands
Implementing custom
commands
Common interface
controls
The Menu control
The ContextMenu
The ToolBar control
The StatusBar control
The Ribbon Control
Introduction
The
FlowDocumentScrollViewer
control
The
FlowDocumentPageViewer
control
The FlowDocumentReader
control
Creating a FlowDocument
from Code-behind
Advanced FlowDocument
content
The RichTextBox control
Misc. controls
The Border control
The Slider control
The ProgressBar control
The WebBrowser control
The WindowsFormsHost
control
The TabControl
Using the TabControl
Tab positions
Styling the TabItems
List controls
The ItemsControl
The ListBox control
The ComboBox control
ListView filtering
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
The Window
Download this entire
tutorial as PDF right
now!
When creating a WPF application, the first thing you will meet is the Window About WPF
class. It serves as the root of a window and provides you with the standard
What is WPF?
border, title bar and maximize, minimize and close buttons. A WPF window is
WPF vs. WinForms
a combination of a XAML (.xaml) file, where the <Window> element is the
root, and a CodeBehind (.cs) file. If you're using Visual Studio (Express) and
you create a new WPF application, it will create a default window for you,
which will look something like this: Getting started
Visual Studio Express
<Window x:Class="WpfApplication1.Window1" Hello, WPF!
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
XAML
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" What is XAML?
Title="Window1" Height="300" Width="300"> Basic XAML
<Grid> Events in XAML
</Grid>
</Window>
A WPF application
Introduction
The Window
The x:class attribute tells the XAML file which class to use, in this case
Working with App.xaml
Window1, which Visual Studio has created for us as well. You will find it in
Command-line parameters
the project tree in VS, as a child node of the XAML file. By default, it looks
Resources
something like this:
Handling exceptions
using System;
using System.Windows;
Basic controls
using System.Windows.Controls;
The TextBlock control
//…more using statements
The TextBlock control - Inline
formatting
namespace WpfApplication1
The Label control
{
The TextBox control
/// <summary>
The CheckBox control
/// Interaction logic for Window1.xaml
and each of them will automatically adjust the window size horizontally, Introduction
vertically or both. The
FlowDocumentScrollViewer
Topmost - The default is false, but if set to true, your Window will stay on top control
of other windows unless minimized. Only useful for special situations. The
FlowDocumentPageViewer
WindowStartupLocation - Controls the initial position of your window. The
control
default is Manual, which means that the window will be initially positioned
The FlowDocumentReader
according to the Top and Left properties of your window. Other options are
control
CenterOwner, which will position the window in the center of it's owner
Creating a FlowDocument
window, and CenterScreen, which will position the window in the center of
from Code-behind
the screen.
Advanced FlowDocument
WindowState - Controls the initial window state. It can be either Normal, content
Maximized or Minimized. The default is Normal, which is what you should The RichTextBox control
use unless you want your window to start either maximized or minimized.
There are lots of other attributes though, so have a look for yourself and then Misc. controls
move on to the next chapter.
The Border control
The Slider control
Previous Next The ProgressBar control
The WebBrowser control
The WindowsFormsHost
control
comments powered by Disqus
The TabControl
Using the TabControl
Tab positions
Styling the TabItems
List controls
The ItemsControl
The ListBox control
The ComboBox control
ListView filtering
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
Working with App.xaml
Download this entire
tutorial as PDF right
now!
App.xaml is the declarative starting point of your application. Visual Studio will About WPF
automatically create it for you when you start a new WPF application,
What is WPF?
including a Code-behind file called App.xaml.cs. They work much like for a
WPF vs. WinForms
Window, where the two files are partial classes, working together to allow you
to work in both markup (XAML) and Code-behind.
App.xaml.cs extends the Application class, which is a central class in a WPF Getting started
Windows application. .NET will go to this class for starting instructions and Visual Studio Express
then start the desired Window or Page from there. This is also the place to Hello, WPF!
subscribe to important application events, like application start, unhandled
exceptions and so on. More about that later.
XAML
One of the most commonly used features of the App.xaml file is to define
global resources that may be used and accessed from all over an application, What is XAML?
for instance global styles. This will be discussed in detail later on. Basic XAML
Events in XAML
App.xaml structure
When creating a new application, the automatically generated App.xaml will
A WPF application
look something like this:
Introduction
The Window
<Application x:Class="WpfTutorialSamples.App"
Working with App.xaml
Command-line parameters
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
Resources
Handling exceptions
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
Basic controls
The TextBlock control
</Application.Resources> The TextBlock control - Inline
</Application> formatting
The Label control
The TextBox control
The main thing to notice here is the StartupUri property. This is actually the The CheckBox control
part that instructs which Window or Page to start up when the application is The RadioButton control
launched. In this case, MainWindow.xaml will be started, but if you would like The PasswordBox control
to use another window as the starting point, you can simply change this.
In some situations, you want more control over how and when the first Panels
window is displayed. In that case, you can remove the StartupUri property Introduction to WPF Panels
and value and then do it all from Code-Behind instead. This will be The Canvas
demonstrated below. The WrapPanel
The StackPanel
App.xaml.cs structure The DockPanel
The matching App.xaml.cs will usually look like this for a new project: The Grid
The Grid - Rows & Columns
The Grid - Units
using System;
The Grid - Spanning
using System.Collections.Generic;
The Grid - GridSplitter
using System.Windows;
Using the Grid: A contact
form
namespace WpfTutorialSamples
{
public partial class App : Application
{ Data binding
Introduction
} Hello, bound world!
} Using the DataContext
The UpdateSourceTrigger
property
You will see how this class extends the Application class, allowing us to do
Responding to changes
stuff on the application level. For instance, you can subscribe to the Startup
Value conversion with
event, where you can manually create your starting window. Here's an
IValueConverter
example:
The StringFormat property
Debugging data bindings
<Application x:Class="WpfTutorialSamples.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
Commands
Introduction
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Using commands
Startup="Application_Startup"> Implementing custom
<Application.Resources></Application.Resources> commands
</Application>
Common interface
Notice how the StartupUri has been replaced with a subscription to the controls
Startup event (subscribing to events through XAML is explained in another The Menu control
chapter). In Code-Behind, you can use the event like this: The ContextMenu
The ToolBar control
using System; The StatusBar control
using System.Collections.Generic; The Ribbon Control
using System.Windows;
{ Introduction
public partial class App : Application The
{ FlowDocumentScrollViewer
control
private void Application_Startup(object The
sender, StartupEventArgs e) FlowDocumentPageViewer
{ control
// Create the startup window The FlowDocumentReader
MainWindow wnd = new MainWindow(); control
// Do stuff here, e.g. to the Creating a FlowDocument
window from Code-behind
wnd.Title = "Something else"; Advanced FlowDocument
// Show the window content
wnd.Show(); The RichTextBox control
}
}
}
Misc. controls
The Border control
The cool thing in this example, compared to just using the StartupUri property,
The Slider control
is that we get to manipulate the startup window before showing it. In this, we
The ProgressBar control
change the title of it, which is not terribly useful, but you could also subscribe
The WebBrowser control
to events or perhaps show a splash screen. When you have all the control,
The WindowsFormsHost
there are many possibilities. We will look deeper into several of them in the
control
next articles of this tutorial.
List controls
The ItemsControl
The ListBox control
The ComboBox control
ListView filtering
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
Command-line parameters in WPF
Download this entire
tutorial as PDF right
now!
Command-line parameters are a technique where you can pass a set of About WPF
parameters to an application that you wish to start, to somehow influence it.
What is WPF?
The most common example is to make the application open with a specific
WPF vs. WinForms
file, e.g. in an editor. You can try this yourself with the built-in Notepad
application of Windows, by running (select Run from the Start menu or press
[WindowsKey-R]):
Getting started
notepad.exe c:\Windows\win.ini Visual Studio Express
Hello, WPF!
This will open Notepad with the win.ini file opened (you may have to adjust
the path to match your system). Notepad simply looks for one or several
parameters and then uses them and your application can do the same!
XAML
Command-line parameters are passed to your WPF application through the What is XAML?
Startup event, which we subscribed to in the App.xaml article. We will do the Basic XAML
same in this example, and then use the value passed on to through the Events in XAML
method arguments. First, the App.xaml file:
Basic controls
The TextBlock control
All we do here is to subscribe to the Startup event, replacing the StartupUri
The TextBlock control - Inline
property. The event is then implemented in App.xaml.cs:
formatting
The Label control
using System; The TextBox control
using System.Collections.Generic; The CheckBox control
using System.Windows;
The StartupEventArgs is what we use here. It's passed into the Application
Data binding
Startup event, with the name e. It has the property Args, which is an array of
strings. Command-line parameters are separated by spaces, unless the Introduction
space is inside a quoted string. Hello, bound world!
Using the DataContext
Testing the command-line parameter The UpdateSourceTrigger
property
If you run the above example, nothing will happen, because no command-line Responding to changes
parameters have been specified. Fortunately, Visual Studio makes it easy to Value conversion with
test this in your application. From the Project menu select "[Project name] IValueConverter
properties" and then go to the Debug tab, where you can define a The StringFormat property
command-line parameter. It should look something like this: Debugging data bindings
Commands
Introduction
Using commands
Implementing custom
commands
Common interface
controls
The Menu control
The ContextMenu
Try running the application and you will see it respond to your parameter. Of
The ToolBar control
course, the message isn't terribly useful. Instead you might want to either
The StatusBar control
pass it to the constructor of your main window or call a public open method
The Ribbon Control
on it, like this:
using System.Collections.Generic;
Introduction
using System.Windows;
The
FlowDocumentScrollViewer
namespace WpfTutorialSamples
control
{
The
public partial class App : Application
FlowDocumentPageViewer
{
control
The FlowDocumentReader
private void Application_Startup(object
control
sender, StartupEventArgs e)
Creating a FlowDocument
{
from Code-behind
MainWindow wnd = new MainWindow();
Advanced FlowDocument
// The OpenFile() method is just
content
an example of what you could do with the
The RichTextBox control
// parameter. The method should be
declared on your MainWindow class, where
// you could use a range of
methods to process the passed file path Misc. controls
if(e.Args.Length == 1) The Border control
wnd.OpenFile(e.Args[0]); The Slider control
wnd.Show(); The ProgressBar control
} The WebBrowser control
} The WindowsFormsHost
} control
Command-line possibilities
The TabControl
In this example, we test if there is exactly one argument and if so, we use it as Using the TabControl
a filename. In a real world example, you might collect several arguments and Tab positions
even use them for options, e.g. toggling a certain feature on or off. You would Styling the TabItems
do that by looping through the entire list of arguments passed while collecting
the information you need to proceed, but that's beyond the scope of this
article.
List controls
The ItemsControl
Previous Next
The ListBox control
The ComboBox control
ListView filtering
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
Resources
Download this entire
tutorial as PDF right
now!
WPF introduces a very handy concept: The ability to store data as a About WPF
resource, either locally for a control, locally for the entire window or globally
What is WPF?
for
the entire application. The data can be pretty much whatever you want,
WPF vs. WinForms
from actual information to a hierarchy of WPF controls. This allows you to
place
data in one place and then use it from or several other places, which is
very useful.
Getting started
The concept is used a lot for styles and templates, which we'll discuss later Visual Studio Express
on in this tutorial, but as it will be illustrated in this chapter, you can
use it for Hello, WPF!
many other things as well. Allow me to demonstrate it with a simple example:
<Window XAML
x:Class="WpfTutorialSamples.WPF_Application.ResourceSample"
What is XAML?
Basic XAML
Events in XAML
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
A WPF application
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib" Introduction
Title="ResourceSample" Height="150" Width="350"> The Window
<Window.Resources> Working with App.xaml
<sys:String x:Key="strHelloWorld">Hello, world! Command-line parameters
</sys:String> Resources
</Window.Resources> Handling exceptions
<StackPanel Margin="10">
<TextBlock Text="{StaticResource strHelloWorld}"
FontSize="56" /> Basic controls
<TextBlock>Just another "<TextBlock Text=" The TextBlock control
{StaticResource strHelloWorld}" />" example, but with The TextBlock control - Inline
resources!</TextBlock> formatting
</StackPanel> The Label control
</Window> The TextBox control
The CheckBox control
Panels
Introduction to WPF Panels
The Canvas
The WrapPanel
The StackPanel
Resources are given a key, using the x:Key attribute, which allows you to The DockPanel
reference it from other parts of the application by using this key, in The Grid
combination with the StaticResource markup extension. In this example, I The Grid - Rows & Columns
just store a simple string, which I then use from two different TextBlock The Grid - Units
controls. The Grid - Spanning
The Grid - GridSplitter
StaticResource vs. DynamicResource Using the Grid: A contact
form
In the examples so far, I have used the StaticResource markup extension to
reference a resource. However, an alternative exists, in form of the
DynamicResource.
Data binding
The main difference is that a static resource is resolved only once, which is at Introduction
the point where the XAML is loaded. If the resource is then changed later
on, Hello, bound world!
this change will not be reflected where you have used the StaticResource. Using the DataContext
The UpdateSourceTrigger
A DynamicResource on the other hand, is resolved once it's actually needed, property
and then again if the resource changes. Think of it as binding to a static
value Responding to changes
vs. binding to a function that monitors this value and sends it to you each Value conversion with
time it's changed - it's not exactly how it works, but it should give you
a better IValueConverter
idea of when to use what. Dynamic resources also allows you to use The StringFormat property
resources which are not even there during design time, e.g. if you add them Debugging data bindings
from Code-behind during the startup of the application.
More resource types Commands
Sharing a simple string was easy, but you can do much more. In the next Introduction
example, I'll also store a complete array of strings, along with a gradient Using commands
brush
to be used for the background. This should give you a pretty good idea Implementing custom
of just how much you can do with resources: commands
<Window
x:Class="WpfTutorialSamples.WPF_Application.ExtendedResource Common interface
controls
The Menu control
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta The ContextMenu
The ToolBar control
The StatusBar control
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" The Ribbon Control
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="ExtendedResourceSample" Height="160"
Width="300" Rich Text controls
Background="{DynamicResource
Introduction
WindowBackgroundBrush}">
The
<Window.Resources>
FlowDocumentScrollViewer
<sys:String x:Key="ComboBoxTitle">Items:
control
</sys:String>
The
FlowDocumentPageViewer
<x:Array x:Key="ComboBoxItems" Type="sys:String">
control
<sys:String>Item #1</sys:String>
The FlowDocumentReader
<sys:String>Item #2</sys:String>
control
<sys:String>Item #3</sys:String>
Creating a FlowDocument
</x:Array>
from Code-behind
Advanced FlowDocument
<LinearGradientBrush
content
x:Key="WindowBackgroundBrush">
The RichTextBox control
<GradientStop Offset="0" Color="Silver"/>
<GradientStop Offset="1" Color="Gray"/>
</LinearGradientBrush>
</Window.Resources> Misc. controls
<StackPanel Margin="10"> The Border control
<Label Content="{StaticResource ComboBoxTitle}" /> The Slider control
<ComboBox ItemsSource="{StaticResource The ProgressBar control
ComboBoxItems}" /> The WebBrowser control
</StackPanel> The WindowsFormsHost
</Window> control
The TabControl
Using the TabControl
Tab positions
Styling the TabItems
List controls
The ItemsControl
The ListBox control
This time, we've added a couple of extra resources, so that our Window now
The ComboBox control
contains a simple string, an array of strings and a LinearGradientBrush. The
string is used for the label, the array of strings is used as items for the
ComboBox control and the gradient brush is used as background for the
The ListView control
entire
window. So, as you can see, pretty much anything can be stored as a
resource. Introduction
A simple ListView
Local and application wide resources ListView, data binding and
ItemTemplate
For now, we have stored resources on a window-level, which means that you ListView with a GridView
can access them from all over the window. How-to: Left aligned column
names
If you only need a given resource for a specific control, you can make it more
ListView grouping
local by adding it to this specific control, instead of the window. It works
ListView sorting
exactly the same way, the only difference being that you can now only
How-to: ListView with
access from inside the scope of the control where you put it:
column sorting
ListView filtering
<StackPanel Margin="10">
<StackPanel.Resources>
<sys:String x:Key="ComboBoxTitle">Items:
The TreeView control
</sys:String>
Introduction
</StackPanel.Resources>
A simple TreeView
<Label Content="{StaticResource ComboBoxTitle}" />
TreeView, data binding and
</StackPanel>
multiple templates
Handling
In this case, we add the resource to the StackPanel and then use it from its Selection/Expansion state
child control, the Label. Other controls inside of the StackPanel could have Lazy loading TreeView items
used it as well, just like children of these child controls would have been able
to access it. Controls outside of this particular StackPanel wouldn't have
access to it, though.
The DataGrid control
If you need the ability to access the resource from several windows, this is Introduction
possible as well. The App.xaml file can contain resources
just like the Custom columns
window and any kind of WPF control, and when you store them in App.xaml, Details row
they are globally accessible in all of windows and user controls of
the project.
It works exactly the same way as when storing and using from a Window:
Styles
<Application x:Class="WpfTutorialSamples.App" Introduction
Using styles
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta Triggers
Multi triggers
Trigger animations
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-
namespace:System;assembly=mscorlib"
Misc.
StartupUri="WPF
The DispatcherTimer
application/ExtendedResourceSample.xaml">
<Application.Resources>
<sys:String x:Key="ComboBoxTitle">Items:
</sys:String> Audio & Video
</Application.Resources> Playing audio
</Application> Playing video
How-to: Complete media
player
Using it is also the same - WPF will automatically go up the scope, from the Speech synthesis
local control to the window and then to App.xaml, to find a given resource: Speech recognition
Resources from Code-behind
So far, we've accessed all of our resources directly from XAML, using a
markup extension. However, you can of course access your resources from
Code-behind
as well, which can be useful in several situations. In the
previous example, we saw how we could store resources in several different
places, so in this
example, we'll be accessing three different resources from
App.xaml:
<Application x:Class="WpfTutorialSamples.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-
namespace:System;assembly=mscorlib"
StartupUri="WPF
application/ResourcesFromCodeBehindSample.xaml">
<Application.Resources>
<sys:String x:Key="strApp">Hello, Application
world!</sys:String>
</Application.Resources>
</Application>
Window:
<Window
x:Class="WpfTutorialSamples.WPF_Application.ResourcesFromCod
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="ResourcesFromCodeBehindSample" Height="175"
Width="250">
<Window.Resources>
<sys:String x:Key="strWindow">Hello, Window world!
</sys:String>
</Window.Resources>
<DockPanel Margin="10" Name="pnlMain">
<DockPanel.Resources>
<sys:String x:Key="strPanel">Hello, Panel
world!</sys:String>
</DockPanel.Resources>
<WrapPanel DockPanel.Dock="Top"
HorizontalAlignment="Center" Margin="10">
<Button Name="btnClickMe"
Click="btnClickMe_Click">Click me!</Button>
</WrapPanel>
</DockPanel>
</Window>
Code-behind:
using System;
using System.Windows;
namespace WpfTutorialSamples.WPF_Application
{
public partial class ResourcesFromCodeBehindSample
: Window
{
public ResourcesFromCodeBehindSample()
{
InitializeComponent();
}
lbResult.Items.Add(this.FindResource("strWindow").ToString()
lbResult.Items.Add(Application.Current.FindResource("strApp"
}
}
}
So, as you can see, we store three different "Hello, world!" messages: One in
App.xaml, one inside the window, and one locally for the main panel. The
interface consists of a button and a ListBox.
In Code-behind, we handle the click event of the button, in which we add
each of the text strings to the ListBox, as seen on the screenshot. We use
the FindResource() method, which will return the resource as an object (if
found), and then we turn it into the string that we know it is by
using the
ToString() method.
Notice how we use the FindResource() method on different scopes - first on
the panel, then on the window and then on the current Application object. It
makes sense to look for the resource where we know it is, but as already
mentioned, if a resource is not found, the
search progresses up the
hierarchy, so in principal, we could have used the FindResource() method on
the panel in all three cases, since it would have
continued up to the window
and later on up to the application level, if not found.
The same is not true the other way around - the search doesn't navigate
down the tree, so you can't start looking for a resource on the application
level,
if it has been defined locally for the control or for the window.
Previous Next
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
Handling exceptions in WPF
Download this entire
tutorial as PDF right
now!
If you're familiar with C# or any of the other .NET languages that you may About WPF
use with WPF, then exception handling should not be new to you: Whenever
What is WPF?
you
have a piece of code that are likely to throw an exception, then you
WPF vs. WinForms
should wrap it in a try-catch block to handle the exception gracefully. For
instance,
consider this example:
Getting started
private void Button_Click(object sender, RoutedEventArgs
e) Visual Studio Express
{ Hello, WPF!
string s = null;
s.Trim();
} XAML
What is XAML?
Obviously it will go wrong, since I try to perform the Trim() method on a Basic XAML
variable that's currently null. If you don't handle the exception, your Events in XAML
application will crash and Windows will have to deal with the problem. As you
can see, that isn't very user friendly:
A WPF application
Introduction
The Window
Working with App.xaml
Command-line parameters
Resources
Handling exceptions
Basic controls
The TextBlock control
The TextBlock control - Inline
formatting
The Label control
In this case, the user would be forced to close your application, due to such a
The TextBox control
simple and easily avoided error. So, if you know that things might go
wrong,
The CheckBox control
then you should use a try-catch block, like this:
However, sometimes even the simplest code can throw an exception, and
instead of wrapping every single line of code with a try- catch block, WPF lets
Data binding
you
handle all unhandled exceptions globally. This is done through the
DispatcherUnhandledException event on the Application class. If Introduction
subscribed to, WPF will call the subscribing method once an exception is Hello, bound world!
thrown which is not handled in your own code. Here's a complete example, Using the DataContext
based on
the stuff we just went through: The UpdateSourceTrigger
property
Responding to changes
<Window
Value conversion with
x:Class="WpfTutorialSamples.WPF_Application.ExceptionHandlin
IValueConverter
The StringFormat property
Debugging data bindings
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Commands
Title="ExceptionHandlingSample" Height="200" Introduction
Width="200"> Using commands
<Grid> Implementing custom
<Button HorizontalAlignment="Center" commands
VerticalAlignment="Center" Click="Button_Click">
Do something bad!
</Button> Common interface
</Grid> controls
</Window>
The Menu control
The ContextMenu
The ToolBar control
using System; The StatusBar control
using System.Windows; The Ribbon Control
namespace WpfTutorialSamples.WPF_Application
{ Rich Text controls
<Application x:Class="WpfTutorialSamples.App"
List controls
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta The ItemsControl
The ListBox control
The ComboBox control
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Summary
Exception handling is a very important part of any application and fortunately,
WPF and .NET makes it very easy to handle exceptions both locally and
globally. You should handle exceptions locally when it makes sense and only
use the global handling as a fallback mechanism, since local handling allows
you to be more specific and deal with the problem in a more specialized way.
Previous Next
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
The TextBlock control
Download this entire
tutorial as PDF right
now!
TextBlock is not a control, per se, since it doesn't inherit from the Control About WPF
class, but it's used much like any other control in the WPF framework, so
What is WPF?
we'll call it a control to keep things simple.
WPF vs. WinForms
The TextBlock control is one of the most fundamental controls in WPF, yet
it's very useful. It allows you to put text on the screen, much like a Label
control does, but in a simpler and less resource demanding way. A common Getting started
understanding is that a Label is for short, one-line texts (but may include e.g. Visual Studio Express
an image), while the TextBlock works very well for multiline strings as well, Hello, WPF!
but can only contain text (strings). Both the Label and the TextBlock offers
their own unique advantages, so what you should use very much depends on
the situation.
XAML
We already used a TextBlock control in the "Hello, WPF!" article, but for now, What is XAML?
let's have a look at the TextBlock in its simplest form: Basic XAML
Events in XAML
<Window
x:Class="WpfTutorialSamples.Basic_controls.TextBlockSample"
A WPF application
Introduction
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta The Window
Working with App.xaml
Command-line parameters
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Resources
Title="TextBlockSample" Height="100" Width="200"> Handling exceptions
<Grid>
<TextBlock>This is a TextBlock</TextBlock>
</Grid> Basic controls
</Window>
The TextBlock control
The TextBlock control - Inline
formatting
The Label control
The TextBox control
The CheckBox control
That's as simple as it comes and if you have read the previous chapters of
this tutorial, then there should be nothing new here. The text between the
Panels
TextBlock is simply a shortcut for setting the Text property of the TextBlock.
Introduction to WPF Panels
For the next example, let's try a longer text to show how the TextBlock deals The Canvas
with that. I've also added a bit of margin, to make it look just a bit better: The WrapPanel
The StackPanel
The DockPanel
<Window
The Grid
x:Class="WpfTutorialSamples.Basic_controls.TextBlockSample"
The Grid - Rows & Columns
The Grid - Units
The Grid - Spanning
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
The Grid - GridSplitter
Using the Grid: A contact
form
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="TextBlockSample" Height="100" Width="200">
<Grid>
<TextBlock Margin="10">This is a TextBlock Data binding
control and it comes with a very long text</TextBlock> Introduction
</Grid> Hello, bound world!
</Window> Using the DataContext
The UpdateSourceTrigger
property
Responding to changes
Value conversion with
IValueConverter
The StringFormat property
Debugging data bindings
Common interface
<Window
controls
x:Class="WpfTutorialSamples.Basic_controls.TextBlockSample"
The Menu control
The ContextMenu
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta The ToolBar control
The StatusBar control
The Ribbon Control
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="TextBlockSample" Height="200" Width="250">
<StackPanel> Rich Text controls
<TextBlock Margin="10" Foreground="Red"> Introduction
This is a TextBlock The
control<LineBreak /> FlowDocumentScrollViewer
with multiple lines of text. control
</TextBlock> The
<TextBlock Margin="10" FlowDocumentPageViewer
TextTrimming="CharacterEllipsis" Foreground="Green"> control
This is a TextBlock control with The FlowDocumentReader
text that may not be rendered completely, which will be control
indicated with an ellipsis. Creating a FlowDocument
</TextBlock> from Code-behind
<TextBlock Margin="10" TextWrapping="Wrap" Advanced FlowDocument
Foreground="Blue"> content
This is a TextBlock control with The RichTextBox control
automatically wrapped text, using the TextWrapping
property.
</TextBlock> Misc. controls
</StackPanel>
The Border control
</Window>
The Slider control
The ProgressBar control
The WebBrowser control
The WindowsFormsHost
control
The TabControl
Using the TabControl
Tab positions
Styling the TabItems
List controls
So, we have three TextBlock controls, each with a different color (using the
Foreground property) for an easier overview. They all handle the fact that The ItemsControl
their text content is too long in different ways: The ListBox control
The ComboBox control
The red TextBlock uses a LineBreak tag to manually break the line at a
designated location. This gives you absolute control over where you want the
text to break onto a new line, but it's not very flexible for most situations. If The ListView control
the user makes the window bigger, the text will still wrap at the same
Introduction
position, even though there may now be room enough to fit the entire text
A simple ListView
onto one line.
ListView, data binding and
The green TextBlock uses the TextTrimming property with the value ItemTemplate
CharacterEllipsis to make the TextBlock show an ellipsis (...) when it can't ListView with a GridView
fit any more text into the control. This is a common way of showing that How-to: Left aligned column
there's more text, but not enough room to show it. This is great when you names
have text that might be too long but you absolutely don't want it to use more ListView grouping
than one line. As an alternative to CharacterEllipsis you may use ListView sorting
WordEllipsis, which will trim the text at the end of the last possible word How-to: ListView with
instead of the last possible character, preventing that a word is only shown in column sorting
part. ListView filtering
The blue TextBlock uses the TextWrapping property with the value Wrap, to
make the TextBlock wrap to the next line whenever it can't fit anymore text The TreeView control
into the previous line. Contrary to the first TextBlock, where we manually Introduction
define where to wrap the text, this happens completely automatic and even A simple TreeView
better: It's also automatically adjusted as soon as the TextBlock get more or TreeView, data binding and
less space available. Try making the window in the example bigger or smaller multiple templates
and you will see how the wrapping is updated to match the situation. Handling
Selection/Expansion state
This was all about dealing with simple strings in the TextBlock. In the next
Lazy loading TreeView items
chapter, we'll look into some of the more advanced functionality of the
TextBlock, which allows us to create text of various styles within the
TextBlock and much more.
The DataGrid control
Previous Next Introduction
Custom columns
Details row
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
The TextBlock control - Inline
formatting Download this entire
tutorial as PDF right
now!
About WPF
In the last article we looked at the core functionality of the TextBlock control:
What is WPF?
Displaying a simple string and wrapping it if necessary. We even used
WPF vs. WinForms
another color than the default for rendering the text, but what if you wanted to
do more than just define a static color for all the text in the TextBlock?
Luckily the TextBlock control supports inline content. These small control-like Getting started
constructs all inherit from the Inline class, which means that they can be Visual Studio Express
rendered inline, as a part of a larger text. As of writing, the supported Hello, WPF!
elements include AnchoredBlock, Bold, Hyperlink, InlineUIContainer, Italic,
LineBreak, Run, Span, and Underline. In the following examples, we'll have a
look at most of them.
XAML
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="TextBlockInlineSample" Height="100"
Basic controls
Width="300">
<Grid> The TextBlock control
<TextBlock Margin="10" The TextBlock control - Inline
TextWrapping="Wrap"> formatting
TextBlock with <Bold>bold</Bold>, The Label control
<Italic>italic</Italic> and The TextBox control
<Underline>underlined</Underline> text. The CheckBox control
Panels
Introduction to WPF Panels
The Canvas
The WrapPanel
The StackPanel
The DockPanel
The Grid
Much like with HTML, you just surround your text with a Bold tag to get bold The Grid - Rows & Columns
text and so on. This makes it very easy to create and display diverse text in The Grid - Units
your applications. The Grid - Spanning
The Grid - GridSplitter
All three of these tags are just child classes of the Span element, each setting Using the Grid: A contact
a specific property on the Span element to create the desired effect. For form
instance, the Bold tag just sets the FontWeight property on the underlying
Span element, the Italic element sets the FontStyle and so on.
Data binding
LineBreak
Introduction
Simply inserts a line break into the text. Please see the previous chapter for Hello, bound world!
an example where we use the LineBreak element. Using the DataContext
The UpdateSourceTrigger
Hyperlink property
Responding to changes
The Hyperlink element allows you to have links in your text. It's rendered with Value conversion with
a style that suits your current Windows theme, which will usually be some IValueConverter
sort of underlined blue text with a red hover effect and a hand mouse cursor. The StringFormat property
You can use the NavigateUri property to define the URL that you wish to Debugging data bindings
navigate to. Here's an example:
<Window Commands
x:Class="WpfTutorialSamples.Basic_controls.TextBlockHyperlin
Introduction
Using commands
Implementing custom
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
commands
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="TextBlockHyperlinkSample" Height="100" Common interface
Width="300"> controls
<Grid> The Menu control
<TextBlock Margin="10" The ContextMenu
TextWrapping="Wrap"> The ToolBar control
This text has a <Hyperlink The StatusBar control
RequestNavigate="Hyperlink_RequestNavigate" The Ribbon Control
NavigateUri="https://www.google.com">link</Hyperlink> in
it.
</TextBlock> Rich Text controls
</Grid>
Introduction
</Window>
The
FlowDocumentScrollViewer
control
The
FlowDocumentPageViewer
control
The FlowDocumentReader
control
Creating a FlowDocument
The Hyperlink is also used inside of WPF Page's, where it can be used to from Code-behind
navigate between pages. In that case, you won't have to specifically handle Advanced FlowDocument
the RequestNavigate event, like we do in the example, but for launching content
external URL's from a regular WPF application, we need a bit of help from The RichTextBox control
this event and the Process class. We subscribe to the RequestNavigate
event, which allows us to launch the linked URL in the users default browser
with a simple event handler like this one in the code behind file: Misc. controls
The Border control
private void Hyperlink_RequestNavigate(object sender, The Slider control
System.Windows.Navigation.RequestNavigateEventArgs e)
The ProgressBar control
{
The WebBrowser control
The WindowsFormsHost
System.Diagnostics.Process.Start(e.Uri.AbsoluteUri);
control
}
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
So as you can see, if none of the other elements doesn't make sense in your
situation or if you just want a blank canvas when starting to format your text, Misc.
the Span element is a great choice. The DispatcherTimer
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="TextBlockCodeBehindSample" Height="100"
Width="300">
<Grid></Grid>
</Window>
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
namespace WpfTutorialSamples.Basic_controls
{
public partial class TextBlockCodeBehindSample :
Window
{
public TextBlockCodeBehindSample()
{
InitializeComponent();
TextBlock tb = new TextBlock();
tb.TextWrapping =
TextWrapping.Wrap;
tb.Margin = new Thickness(10);
tb.Inlines.Add("An example on ");
tb.Inlines.Add(new Run("the
TextBlock control ") { FontWeight = FontWeights.Bold });
tb.Inlines.Add("using ");
tb.Inlines.Add(new Run("inline ")
{ FontStyle = FontStyles.Italic });
tb.Inlines.Add(new Run("text
formatting ") { Foreground = Brushes.Blue });
tb.Inlines.Add("from ");
tb.Inlines.Add(new Run("Code-
Behind") { TextDecorations = TextDecorations.Underline });
tb.Inlines.Add(".");
this.Content = tb;
}
}
}
It's great to have the possibility, and it can be necessary to do it like this in
some cases, but this example will probably make you appreciate XAML even
more.
Previous Next
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
The Label control
Download this entire
tutorial as PDF right
now!
The Label control, in its most simple form, will look very much like the About WPF
TextBlock which we used in another article. You will quickly notice though
What is WPF?
that instead of a Text property, the Label has a Content property. The reason
WPF vs. WinForms
for that is that the Label can host any kind of control directly inside of it,
instead of just text. This content can be a string as well though, as you will
see in this first and very basic example:
Getting started
<Window Visual Studio Express
x:Class="WpfTutorialSamples.Basic_controls.LabelControlSampl Hello, WPF!
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta XAML
What is XAML?
Basic XAML
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Events in XAML
Title="LabelControlSample" Height="100"
Width="200">
<Grid>
A WPF application
<Label Content="This is a Label control."
Introduction
/>
The Window
</Grid>
Working with App.xaml
</Window>
Command-line parameters
Resources
Handling exceptions
Basic controls
The TextBlock control
The TextBlock control - Inline
Another thing you might notice is the fact that the Label, by default, has a bit formatting
of padding, allowing the text to be rendered a few pixels away from the top, The Label control
left corner. This is not the case for the TextBlock control, where you will have The TextBox control
to specify it manually. The CheckBox control
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta Commands
Introduction
Using commands
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Implementing custom
Title="LabelControlSample" Height="180"
commands
Width="250">
<StackPanel Margin="10">
<Label Content="_Name:" Target="{Binding
Common interface
ElementName=txtName}" />
controls
<TextBox Name="txtName" />
<Label Content="_Mail:" Target="{Binding The Menu control
ElementName=txtMail}" /> The ContextMenu
<TextBox Name="txtMail" /> The ToolBar control
</StackPanel> The StatusBar control
</Window> The Ribbon Control
Introduction
The
FlowDocumentScrollViewer
control
The
FlowDocumentPageViewer
control
The FlowDocumentReader
control
The screenshot shows our sample dialog as it looks when the Alt key is Creating a FlowDocument
pressed. Try running it, holding down the [Alt] key and then pressing N and from Code-behind
M. You will see how focus is moved between the two textboxes. Advanced FlowDocument
content
So, there's several new concepts here. First of all, we define the access key The RichTextBox control
by placing an underscore (_) before the character. It doesn't have to be the
first character, it can be before any of the characters in your label content.
The common practice is to use the first character that's not already used as Misc. controls
an access key for another control. The Border control
The Slider control
We use the Target property to connect the Label and the designated control.
The ProgressBar control
We use a standard WPF binding for this, using the ElementName property,
The WebBrowser control
all of which we will describe later on in this tutorial. The binding is based on
The WindowsFormsHost
the name of the control, so if you change this name, you will also have to
control
remember to change the binding.
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
This is just an extended version of the previous example - instead of a simple
text string, our Label will now host both and image and a piece of text (inside
the AccessText control, which allows us to still use an access key for the
Audio & Video
label). Both controls are inside a horizontal StackPanel, since the Label, just
Playing audio
like any other ContentControl derivate, can only host one direct child control.
Playing video
The Image control, described later in this tutorial, uses a remote image - this How-to: Complete media
is ONLY for demonstrational purposes and is NOT a good idea for most real player
life applications. Speech synthesis
Speech recognition
Summary
In most situations, the Label control does exactly what the name implies: It
acts as a text label for another control. This is the primary purpose of it. For
most other cases, you should probably use a TextBlock control or one of the
other text containers that WPF offers.
Previous Next
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
The TextBox control
Download this entire
tutorial as PDF right
now!
The TextBox control is the most basic text-input control found in WPF, About WPF
allowing the end-user to write plain text, either on a single line, for dialog
What is WPF?
input, or in multiple lines, like an editor.
WPF vs. WinForms
Single-line TextBox
The TextBox control is such a commonly used thing that you actually don't Getting started
have to use any properties on it, to have a full-blown editable text field.
Visual Studio Express
Here's a barebone example:
Hello, WPF!
<Window
x:Class="WpfTutorialSamples.Basic_controls.TextBoxSample"
XAML
What is XAML?
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
Basic XAML
Events in XAML
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="TextBoxSample" Height="80" Width="250">
<StackPanel Margin="10"> A WPF application
<TextBox /> Introduction
</StackPanel> The Window
</Window> Working with App.xaml
Command-line parameters
Resources
Handling exceptions
Basic controls
The TextBlock control
That's all you need to get a text field. I added the text after running the The TextBlock control - Inline
sample and before taking the screenshot, but you can do it through markup formatting
as
well, to pre-fill the textbox, using the Text property: The Label control
The TextBox control
<TextBox Text="Hello, world!" /> The CheckBox control
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Data binding
Title="TextBoxSample" Height="160" Width="280">
<Grid Margin="10"> Introduction
<TextBox AcceptsReturn="True" Hello, bound world!
TextWrapping="Wrap" /> Using the DataContext
</Grid> The UpdateSourceTrigger
</Window> property
Responding to changes
Value conversion with
IValueConverter
The StringFormat property
Debugging data bindings
Commands
Introduction
Using commands
Implementing custom
I have added two properties: The AcceptsReturn makes the TextBox into a commands
multi-line control by allowing the use of the Enter/Return key to go to the next
line, and the TextWrapping property, which will make the text wrap
automatically when the end of a line is reached. Common interface
controls
Spellcheck with TextBox The Menu control
The ContextMenu
As an added bonus, the TextBox control actually comes with automatic spell
The ToolBar control
checking for English and a couple of other languages (as of writing, English,
The StatusBar control
French, German, and Spanish languages are supported). It works much like
The Ribbon Control
in Microsoft Word, where spelling errors are underlined and you can right-
click it
for suggested alternatives. Enabling spell checking is very easy:
x:Class="WpfTutorialSamples.Basic_controls.TextBoxSample" Introduction
The
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta FlowDocumentScrollViewer
control
The
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" FlowDocumentPageViewer
Title="TextBoxSample" Height="160" Width="280"> control
<Grid Margin="10"> The FlowDocumentReader
<TextBox AcceptsReturn="True" control
TextWrapping="Wrap" SpellCheck.IsEnabled="True" Creating a FlowDocument
Language="en-US" /> from Code-behind
</Grid> Advanced FlowDocument
</Window> content
The RichTextBox control
Misc. controls
The Border control
The Slider control
The ProgressBar control
The WebBrowser control
The WindowsFormsHost
control
We have used the previous, multi-line textbox example as the basis and then
I have added two new properties: The attached property from the SpellCheck The TabControl
class called IsEnabled, which simply enables spell checking on the parent Using the TabControl
control, and the Language property, which instructs the spell checker which Tab positions
language to use. Styling the TabItems
Working with TextBox selections
Just like any other editable control in Windows, the TextBox allows for List controls
selection of text, e.g. to delete an entire word at once or to copy a piece of The ItemsControl
the
text to the clipboard. The WPF TextBox has several properties for The ListBox control
working with selected text, all of them which you can read or even modify. In The ComboBox control
the next
example, we will be reading these properties:
ListView filtering
DockPanel.Dock="Top" />
<TextBox Name="txtStatus"
AcceptsReturn="True" TextWrapping="Wrap" IsReadOnly="True"
The TreeView control
/>
Introduction
</DockPanel> A simple TreeView
</Window> TreeView, data binding and
multiple templates
Handling
Selection/Expansion state
The example consists of two TextBox controls: One for editing and one for
Lazy loading TreeView items
outputting the current selection status to. For this, we set the IsReadOnly
property to true, to prevent editing of the status TextBox. We subscribe the
SelectionChanged event on the first TextBox, which we handle in the
Code-
behind: The DataGrid control
Introduction
using System; Custom columns
using System.Text; Details row
using System.Windows;
using System.Windows.Controls;
Styles
namespace WpfTutorialSamples.Basic_controls Introduction
{ Using styles
public partial class TextBoxSelectionSample : Triggers
Window Multi triggers
{ Trigger animations
public TextBoxSelectionSample()
{
InitializeComponent();
Misc.
}
The DispatcherTimer
private void
TextBox_SelectionChanged(object sender, RoutedEventArgs e)
{ Audio & Video
TextBox textBox = sender as Playing audio
TextBox; Playing video
txtStatus.Text = "Selection starts How-to: Complete media
at character #" + textBox.SelectionStart + player
Environment.NewLine; Speech synthesis
txtStatus.Text += "Selection is " Speech recognition
+ textBox.SelectionLength + " character(s) long" +
Environment.NewLine;
txtStatus.Text += "Selected text:
'" + textBox.SelectedText + "'";
}
}
}
We use three interesting properties to accomplish this:
SelectionStart
, which gives us the current cursor position or if there's a
selection: Where it starts.
SelectionLength
, which gives us the length of the current selection, if any.
Otherwise it will just return 0.
SelectedText
, which gives us the currently selected string if there's a
selection. Otherwise an empty string is returned.
Modifying the selection
All of these properties are both readable and writable, which means that you
can modify them as well. For instance, you can set the SelectionStart and
SelectionLength properties to select a custom range of text, or you can use
the SelectedText property to insert and select a string. Just remember that
the
TextBox has to have focus, e.g. by calling the Focus() method first, for
this to work.
Previous Next
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
The CheckBox control
Download this entire
tutorial as PDF right
now!
The CheckBox control allows the end-user to toggle an option on or off, About WPF
usually reflecting a Boolean value in the Code-behind. Let's jump straight into
What is WPF?
an
example, in case you're not sure how a CheckBox looks:
WPF vs. WinForms
<Window
x:Class="WpfTutorialSamples.Basic_controls.CheckBoxSample"
Getting started
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta Visual Studio Express
Hello, WPF!
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="CheckBoxSample" Height="140" Width="250"> XAML
<StackPanel Margin="10"> What is XAML?
<Label FontWeight="Bold">Application Basic XAML
Options</Label> Events in XAML
<CheckBox>Enable feature ABC</CheckBox>
<CheckBox IsChecked="True">Enable feature
XYZ</CheckBox>
A WPF application
<CheckBox>Enable feature WWW</CheckBox>
Introduction
</StackPanel>
The Window
</Window>
Working with App.xaml
Command-line parameters
Resources
Handling exceptions
Basic controls
The TextBlock control
The TextBlock control - Inline
formatting
The Label control
As you can see, the CheckBox is very easy to use. On the second The TextBox control
CheckBox, I use the IsChecked property to have it checked by default, but The CheckBox control
Custom content Panels
Introduction to WPF Panels
The CheckBox control inherits from the ContentControl class, which means
The Canvas
that it can take custom content and display next to it. If you just specify a
The WrapPanel
piece of text, like I did in the example above, WPF will put it inside a
The StackPanel
TextBlock control and display it, but this is just a shortcut to make things
The DockPanel
easier for you. You can use any type of control inside of it, as we'll see in the
The Grid
next example:
The Grid - Rows & Columns
The Grid - Units
<Window The Grid - Spanning
x:Class="WpfTutorialSamples.Basic_controls.CheckBoxSample"
The Grid - GridSplitter
Using the Grid: A contact
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
form
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Data binding
Title="CheckBoxSample" Height="140" Width="250">
<StackPanel Margin="10"> Introduction
<Label FontWeight="Bold">Application Hello, bound world!
Options</Label> Using the DataContext
<CheckBox> The UpdateSourceTrigger
<TextBlock> property
Enable feature <Run Responding to changes
Foreground="Green" FontWeight="Bold">ABC</Run> Value conversion with
</TextBlock> IValueConverter
</CheckBox> The StringFormat property
<CheckBox IsChecked="True"> Debugging data bindings
<WrapPanel>
<TextBlock>
Enable feature Commands
<Run FontWeight="Bold">XYZ</Run> Introduction
</TextBlock> Using commands
<Image Implementing custom
Source="/WpfTutorialSamples;component/Images/question.png" commands
Width="16" Height="16" Margin="5,0" />
</WrapPanel>
</CheckBox>
Common interface
<CheckBox>
controls
<TextBlock>
The Menu control
Enable feature <Run
The ContextMenu
Foreground="Blue" TextDecorations="Underline"
The ToolBar control
FontWeight="Bold">WWW</Run>
The StatusBar control
</TextBlock>
The Ribbon Control
</CheckBox>
</StackPanel>
</Window>
Rich Text controls
Introduction
The
FlowDocumentScrollViewer
control
The
FlowDocumentPageViewer
control
The FlowDocumentReader
control
Creating a FlowDocument
As you can see from the sample markup, you can do pretty much whatever
from Code-behind
you want with the content. On all three check boxes, I do something
Advanced FlowDocument
differently with
the text, and on the middle one I even throw in an Image
content
control. By specifying a control as the content, instead of just text, we get
The RichTextBox control
much more control of
the appearance, and the cool thing is that no matter
which part of the content you click on, it will activate the CheckBox and
toggle it on or off.
Misc. controls
The IsThreeState property The Border control
The Slider control
As mentioned, the CheckBox usually corresponds to a boolean value, which
The ProgressBar control
means that it only has two states: true or false (on or off). However, since a
The WebBrowser control
boolean data type might be nullable, effectively allowing for a third option
The WindowsFormsHost
(true, false or null), the CheckBox control can also support this case. By
control
setting the IsThreeState property to true, the CheckBox will get a third state
called "the indeterminate state".
A common usage for this is to have a "Enable all" CheckBox, which can The TabControl
control a set of child checkboxes, as well as show their collective state. Our Using the TabControl
example shows how you may create a list of features that can be toggled on Tab positions
and off, with a common "Enable all" CheckBox in the top: Styling the TabItems
<Window
x:Class="WpfTutorialSamples.Basic_controls.CheckBoxThreeStat List controls
The ItemsControl
The ListBox control
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
The ComboBox control
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
The ListView control
Title="CheckBoxThreeStateSample" Height="170"
Width="300"> Introduction
<StackPanel Margin="10"> A simple ListView
<Label FontWeight="Bold">Application ListView, data binding and
Options</Label> ItemTemplate
<StackPanel Margin="10,5"> ListView with a GridView
<CheckBox IsThreeState="True" How-to: Left aligned column
Name="cbAllFeatures" names
Checked="cbAllFeatures_CheckedChanged" ListView grouping
Unchecked="cbAllFeatures_CheckedChanged">Enable ListView sorting
all</CheckBox> How-to: ListView with
<StackPanel Margin="20,5"> column sorting
Styles
using System;
Introduction
using System.Windows;
Using styles
Triggers
namespace WpfTutorialSamples.Basic_controls
Multi triggers
{
Trigger animations
public partial class CheckBoxThreeStateSample :
Window
{
Misc.
public CheckBoxThreeStateSample()
{ The DispatcherTimer
InitializeComponent();
}
Audio & Video
Playing audio
private void Playing video
cbAllFeatures_CheckedChanged(object sender, How-to: Complete media
RoutedEventArgs e) player
{ Speech synthesis
bool newVal = Speech recognition
(cbAllFeatures.IsChecked == true);
cbFeatureAbc.IsChecked = newVal;
cbFeatureXyz.IsChecked = newVal;
cbFeatureWww.IsChecked = newVal;
}
private void
cbFeature_CheckedChanged(object sender, RoutedEventArgs e)
{
cbAllFeatures.IsChecked = null;
if((cbFeatureAbc.IsChecked ==
}
}
This example works from two different angles: If you check or uncheck the
"Enable all" CheckBox, then all of the child check boxes, each representing
an
application feature in our example, is either checked or unchecked. It also
works the other way around though, where checking or unchecking a child
CheckBox affects the "Enable all" CheckBox state: If they are all checked or
unchecked, then the "Enable all" CheckBox gets the same state - otherwise
the
value will be left with a null, which forces the CheckBox into the
indeterminate state.
All of this behavior can be seen on the screenshots above, and is achieved
by subscribing to the Checked and Unchecked events of the CheckBox
controls. In
a real world example, you would likely bind the values instead,
but this example shows the basics of using the IsThreeState property to
create a "Toggle
all" effect.
Previous Next
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
The RadioButton control
Download this entire
tutorial as PDF right
now!
The RadioButton control allows you to give your user a list of possible About WPF
options, with only one of them selected at the same time. You can achieve
What is WPF?
the same
effect, using less space, with the ComboBox control, but a set of
WPF vs. WinForms
radio buttons tend to give the user a better overview of the options they have.
<Window
Getting started
x:Class="WpfTutorialSamples.Basic_controls.RadioButtonSample
Visual Studio Express
Hello, WPF!
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
XAML
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" What is XAML?
Title="RadioButtonSample" Height="150" Basic XAML
Width="250"> Events in XAML
<StackPanel Margin="10">
<Label FontWeight="Bold">Are you ready?
</Label>
A WPF application
<RadioButton>Yes</RadioButton>
Introduction
<RadioButton>No</RadioButton>
The Window
<RadioButton
Working with App.xaml
IsChecked="True">Maybe</RadioButton>
Command-line parameters
</StackPanel>
Resources
</Window>
Handling exceptions
Basic controls
The TextBlock control
The TextBlock control - Inline
formatting
The Label control
The TextBox control
The CheckBox control
RadioButton groups The StackPanel
The DockPanel
If you try running the example above, you will see that, as promised, only one The Grid
RadioButton can be checked at the same time. But what if you want several The Grid - Rows & Columns
groups of radio buttons, each with their own, individual selection? This is The Grid - Units
what the GroupName property comes into play, which allows you
to specify The Grid - Spanning
which radio buttons belong together. Here's an example: The Grid - GridSplitter
Using the Grid: A contact
<Window form
x:Class="WpfTutorialSamples.Basic_controls.RadioButtonSample
Data binding
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta Introduction
Hello, bound world!
Using the DataContext
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" The UpdateSourceTrigger
Title="RadioButtonSample" Height="230" property
Width="250"> Responding to changes
<StackPanel Margin="10"> Value conversion with
<Label FontWeight="Bold">Are you ready? IValueConverter
</Label> The StringFormat property
<RadioButton Debugging data bindings
GroupName="ready">Yes</RadioButton>
<RadioButton
GroupName="ready">No</RadioButton>
Commands
<RadioButton GroupName="ready"
Introduction
IsChecked="True">Maybe</RadioButton>
Using commands
Implementing custom
<Label FontWeight="Bold">Male or female?
commands
</Label>
<RadioButton
GroupName="sex">Male</RadioButton>
<RadioButton Common interface
GroupName="sex">Female</RadioButton> controls
<RadioButton GroupName="sex" The Menu control
Custom content
The RadioButton inherits from the ContentControl class, which means that it Misc. controls
can take custom content and display next to it. If you just specify a piece of The Border control
text, like I did in the example above, WPF will put it inside a TextBlock control The Slider control
and display it, but this is just a shortcut to make things easier for
you. You The ProgressBar control
can use any type of control inside of it, as we'll see in the next example: The WebBrowser control
The WindowsFormsHost
<Window control
x:Class="WpfTutorialSamples.Basic_controls.RadioButtonCustom
The TabControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
Using the TabControl
Tab positions
Styling the TabItems
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="RadioButtonCustomContentSample"
Height="150" Width="250">
List controls
<StackPanel Margin="10">
<Label FontWeight="Bold">Are you ready? The ItemsControl
</Label> The ListBox control
<RadioButton> The ComboBox control
<WrapPanel>
<Image
Source="/WpfTutorialSamples;component/Images/accept.png" The ListView control
Width="16" Height="16" Margin="0,0,5,0" /> Introduction
<TextBlock Text="Yes" A simple ListView
Foreground="Green" /> ListView, data binding and
</WrapPanel> ItemTemplate
Styles
Introduction
Using styles
Triggers
Multi triggers
Markup-wise, this example gets a bit heavy, but the concept is pretty simple.
Trigger animations
For each RadioButton, we have a WrapPanel with an image and a piece of
text
inside of it. Since we now take control of the text using a TextBlock
control, this also allows us to format the text in any way we want to. For this
example, I have changed the text color to match the choice. An Image control Misc.
(read more about those later) is used to display an image for each choice. The DispatcherTimer
Notice how you can click anywhere on the RadioButton, even on the image
or the text, to toggle it on, because we have specified it as content of the
Audio & Video
RadioButton. If you had placed it as a separate panel, next to the
RadioButton, the user would have to click directly on the round circle of the Playing audio
RadioButton to activate it, which is less practical. Playing video
How-to: Complete media
player
Previous Next Speech synthesis
Speech recognition
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
The PasswordBox control
Download this entire
tutorial as PDF right
now!
For editing regular text in WPF we have the TextBox, but what about editing About WPF
passwords? The functionality is very much the same, but we want WPF to
What is WPF?
display
something else than the actual characters when typing in a password,
WPF vs. WinForms
to shield it from nosy people looking over your shoulder. For this purpose,
WPF has
the PasswordBox control, which is just as easy to use as the
TextBox. Allow me to illustrate with an example:
Getting started
<Window Visual Studio Express
x:Class="WpfTutorialSamples.Basic_controls.PasswordBoxSample Hello, WPF!
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta XAML
What is XAML?
Basic XAML
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Events in XAML
Title="PasswordBoxSample" Height="160"
Width="300">
<StackPanel Margin="10">
A WPF application
<Label>Text:</Label>
Introduction
<TextBox />
The Window
<Label>Password:</Label>
Working with App.xaml
<PasswordBox />
Command-line parameters
</StackPanel>
Resources
</Window>
Handling exceptions
Basic controls
The TextBlock control
The TextBlock control - Inline
formatting
The Label control
The TextBox control
The CheckBox control
Common interface
controls
The Menu control
The ContextMenu
The ToolBar control
The StatusBar control
Notice how the characters are now X's instead, and that I was only allowed to
The Ribbon Control
enter 6 characters in the box.
PasswordBox and binding
Rich Text controls
When you need to obtain the password from the PasswordBox, you can use
Introduction
the Password property from Code-behind. However, for security
reasons,
The
the Password property is not implemented as a dependency property, which
FlowDocumentScrollViewer
means that you can't bind to it.
control
This may or may not be important to you - as already stated, you can still The
read the password from Code-behind, but for MVVM implementations or if FlowDocumentPageViewer
you just
love data bindings, a workaround has been developed. You can read control
much more about it here:
http://blog.functionalfun.net/2008/06/wpf- The FlowDocumentReader
passwordbox-and-data-binding.html control
Creating a FlowDocument
from Code-behind
Previous Next Advanced FlowDocument
content
The RichTextBox control
The TabControl
Using the TabControl
Tab positions
Styling the TabItems
List controls
The ItemsControl
The ListBox control
The ComboBox control
ListView filtering
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
Introduction to WPF panels
Download this entire
tutorial as PDF right
now!
Panels are one of the most important control types of WPF. They act as About WPF
containers for other controls and control the layout of your windows/pages.
What is WPF?
Since a window can only contain ONE child control, a panel is often used to
WPF vs. WinForms
divide up the space into areas, where each area can contain a control or
another panel (which is also a control, of course).
Panels come in several different flavors, with each of them having its own way Getting started
of dealing with layout and child controls. Picking the right panel is therefore Visual Studio Express
essential to getting the behavior and layout you want, and especially in the Hello, WPF!
start of your WPF career, this can be a difficult job. The next section will
describe each of the panels shortly and give you an idea of when to use it.
After that, move on to the next chapters, where each of the panels will be
XAML
described in detail.
What is XAML?
Canvas Basic XAML
Events in XAML
A simple panel, which mimics the WinForms way of doing things. It allows
you to assign specific coordinates to each of the child controls, giving you
total control of the layout. This is not very flexible though, because you have A WPF application
to manually move the child controls around and make sure that they align the
Introduction
way you want them to. Use it (only) when you want complete control of the
The Window
child control positions.
Working with App.xaml
based on the largest item, each item is stretched to take up the full width or The RadioButton control
height. Use the StackPanel when you want a list of controls that takes up all The PasswordBox control
the available room, without wrapping.
DockPanel Panels
The DockPanel allows you to dock the child controls to the top, bottom, left or Introduction to WPF Panels
right. By default, the last control, if not given a specific dock position, will fill The Canvas
the remaining space. You can achieve the same with the Grid panel, but for The WrapPanel
the simpler situations, the DockPanel will be easier to use. Use the The StackPanel
DockPanel whenever you need to dock one or several controls to one of the The DockPanel
sides, like for dividing up the window into specific areas. The Grid
The Grid - Rows & Columns
Grid The Grid - Units
The Grid - Spanning
The Grid is probably the most complex of the panel types. A Grid can contain
The Grid - GridSplitter
multiple rows and columns. You define a height for each of the rows and a
Using the Grid: A contact
width for each of the columns, in either an absolute amount of pixels, in a
form
percentage of the available space or as auto, where the row or column will
automatically adjust its size depending on the content. Use the Grid when the
other panels doesn't do the job, e.g. when you need multiple columns and
often in combination with the other panels.
Data binding
Introduction
UniformGrid Hello, bound world!
Using the DataContext
The UniformGrid is just like the Grid, with the possibility of multiple rows and
The UpdateSourceTrigger
columns, but with one important difference: All rows and columns will have
property
the same size! Use this when you need the Grid behavior without the need to
Responding to changes
specify different sizes for the rows and columns.
Value conversion with
IValueConverter
Previous Next The StringFormat property
Debugging data bindings
Common interface
controls
The Menu control
The ContextMenu
The ToolBar control
The StatusBar control
The Ribbon Control
Introduction
The
FlowDocumentScrollViewer
control
The
FlowDocumentPageViewer
control
The FlowDocumentReader
control
Creating a FlowDocument
from Code-behind
Advanced FlowDocument
content
The RichTextBox control
Misc. controls
The Border control
The Slider control
The ProgressBar control
The WebBrowser control
The WindowsFormsHost
control
The TabControl
Using the TabControl
Tab positions
Styling the TabItems
List controls
The ItemsControl
The ListBox control
The ComboBox control
ListView filtering
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
The Canvas control
Download this entire
tutorial as PDF right
now!
The Canvas is probably the simplest Panel of them all. It doesn't really do About WPF
anything by default, it just allows you to put controls in it and then position
What is WPF?
them yourself using explicit coordinates.
WPF vs. WinForms
If you have ever used another UI library like WinForms, this will probably
make you feel right at home, but while it can be tempting to have absolute
control of all the child controls, this also means that the Panel won't do Getting started
anything for you once the user starts resizing your window, if you localize Visual Studio Express
absolutely positioned text or if the content is scaled. Hello, WPF!
More about that later, let's get into a simple example. This one is mostly
about showing you just how little the Canvas does by default:
XAML
What is XAML?
<Window x:Class="WpfTutorialSamples.Panels.Canvas"
Basic XAML
Events in XAML
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
Basic controls
The TextBlock control
The TextBlock control - Inline
formatting
The Label control
The TextBox control
The CheckBox control
As you can see, even though we have two buttons, they are both placed in Panels
the exact same place, so only the last one is visible. The Canvas does
Introduction to WPF Panels
absolutely
nothing until you start giving coordinates to the child controls. This
The Canvas
is done using the Left, Right, Top and Bottom attached properties from the
The WrapPanel
Canvas
control.
The StackPanel
The DockPanel
These properties allow you to specify the position relative to the four edges of
The Grid
the Canvas. By default, they are all set to NaN (Not a Number), which will
The Grid - Rows & Columns
make the Canvas place them in the upper left corner, but as mentioned, you
The Grid - Units
can easily change this:
The Grid - Spanning
The Grid - GridSplitter
<Window x:Class="WpfTutorialSamples.Panels.Canvas"
Using the Grid: A contact
form
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
Data binding
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Canvas" Height="200" Width="200"> Introduction
<Canvas> Hello, bound world!
<Button Canvas.Left="10">Top left</Button> Using the DataContext
<Button Canvas.Right="10">Top The UpdateSourceTrigger
right</Button> property
<Button Canvas.Left="10" Responding to changes
Canvas.Bottom="10">Bottom left</Button> Value conversion with
<Button Canvas.Right="10" IValueConverter
Canvas.Bottom="10">Bottom right</Button> The StringFormat property
</Canvas> Debugging data bindings
</Window>
Commands
Introduction
Using commands
Implementing custom
commands
Common interface
controls
The Menu control
The ContextMenu
The ToolBar control
Notice how I only set the property or properties that I need. For the first two The StatusBar control
buttons, I only wish to specify a value for the X axis, so I use the Left
and The Ribbon Control
Right properties to push the buttons towards the center, from each direction.
For the bottom buttons, I use both Left/Right and Bottom to push them
Rich Text controls
towards the center in both directions. You will usually specify either a Top or
a
Bottom value and/or a Left or a Right value. Introduction
The
As mentioned, since the Canvas gives you complete control of positions, it FlowDocumentScrollViewer
won't really care whether or not there's enough room for all your controls or if control
one is on top of another. This makes it a bad choice for pretty much any kind The
of dialog design, but the Canvas is, as the name implies, great for at least FlowDocumentPageViewer
one thing: Painting. WPF has a bunch of controls that you can place inside a control
Canvas, to make nice illustrations. The FlowDocumentReader
control
Z-Index Creating a FlowDocument
from Code-behind
In the next example, we'll use a couple of the shape related controls of WPF
Advanced FlowDocument
to illustrate another very important concept when using the Canvas: Z-Index.
content
Normally, if two controls within a Canvas overlaps, the one defined last in the
The RichTextBox control
markup will take precedence and overlap the other(s). However, by using the
attached ZIndex property on the Panel class, this can easily be changed.
First, an example where we don't use z-index at all: Misc. controls
The Border control
<Window x:Class="WpfTutorialSamples.Panels.CanvasZIndex" The Slider control
The ProgressBar control
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta The WebBrowser control
The WindowsFormsHost
control
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="CanvasZIndex" Height="275" Width="260">
<Canvas> The TabControl
<Ellipse Fill="Gainsboro" Canvas.Left="25" Using the TabControl
Canvas.Top="25" Width="200" Height="200" /> Tab positions
<Rectangle Fill="LightBlue" Canvas.Left="25" Styling the TabItems
Canvas.Top="25" Width="50" Height="50" />
<Rectangle Fill="LightCoral" Canvas.Left="50"
Canvas.Top="50" Width="50" Height="50" />
List controls
<Rectangle Fill="LightCyan" Canvas.Left="75"
The ItemsControl
Notice that because each of the rectangles are defined after the circle, they The TreeView control
all overlap the circle, and each of them will overlap the previously defined Introduction
one. Let's try changing that: A simple TreeView
TreeView, data binding and
<Window x:Class="WpfTutorialSamples.Panels.CanvasZIndex" multiple templates
Handling
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta Selection/Expansion state
Lazy loading TreeView items
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="CanvasZIndex" Height="275" Width="260"> The DataGrid control
<Canvas> Introduction
<Ellipse Panel.ZIndex="2" Fill="Gainsboro" Custom columns
Canvas.Left="25" Canvas.Top="25" Width="200" Height="200" Details row
/>
<Rectangle Panel.ZIndex="3" Fill="LightBlue"
Canvas.Left="25" Canvas.Top="25" Width="50" Height="50" />
Styles
<Rectangle Panel.ZIndex="2" Fill="LightCoral"
Introduction
Canvas.Left="50" Canvas.Top="50" Width="50" Height="50" />
Using styles
<Rectangle Panel.ZIndex="4" Fill="LightCyan"
Triggers
Canvas.Left="75" Canvas.Top="75" Width="50" Height="50" />
Multi triggers
</Canvas>
Trigger animations
</Window>
Misc.
The DispatcherTimer
Playing audio
Playing video
How-to: Complete media
player
Speech synthesis
Speech recognition
The default ZIndex value is 0, but we assign a new one to each of the
shapes. The rule is that the element with the higher z-index overlaps the
ones with
the lower values. If two values are identical, the last defined
element "wins". As you can see from the screenshot, changing the ZIndex
property gives
quite another look.
Previous Next
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
The WrapPanel control
Download this entire
tutorial as PDF right
now!
The WrapPanel will position each of its child controls next to the other, About WPF
horizontally (default) or vertically, until there is no more room, where it will
What is WPF?
wrap to the next line and then continue. Use it when you want a vertical or
WPF vs. WinForms
horizontal list controls that automatically wraps when there's no more room.
When the WrapPanel uses the Horizontal orientation, the child controls will be
given the same height, based on the tallest item. When the WrapPanel is the Getting started
Vertical orientation, the child controls will be given the same width, based on Visual Studio Express
the widest item. Hello, WPF!
In the first example, we'll check out a WrapPanel with the default (Horizontal)
orientation:
XAML
What is XAML?
<Window x:Class="WpfTutorialSamples.Panels.WrapPanel"
Basic XAML
Events in XAML
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
Panels
Introduction to WPF Panels
The Canvas
Notice how I set a specific height on one of the buttons in the second row. In The WrapPanel
the resulting screenshot, you will see that this causes the entire row of The StackPanel
buttons to have the same height instead of the height required, as seen on The DockPanel
the first row. You will also notice that the panel does exactly what the name The Grid
implies: It wraps the content when it can't fit any more of it in. In this case, the The Grid - Rows & Columns
fourth button couldn't fit in on the first line, so it automatically wraps to the The Grid - Units
next line. The Grid - Spanning
The Grid - GridSplitter
Should you make the window, and thereby the available space, smaller, you Using the Grid: A contact
will see how the panel immediately adjusts to it: form
Data binding
Introduction
Hello, bound world!
Using the DataContext
The UpdateSourceTrigger
property
Responding to changes
Value conversion with
IValueConverter
All of this behavior is also true when you set the Orientation to Vertical. Here's
The StringFormat property
the exact same example as before, but with a Vertical WrapPanel:
Debugging data bindings
<Window x:Class="WpfTutorialSamples.Panels.WrapPanel"
Commands
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
Introduction
Using commands
Implementing custom
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
commands
Title="WrapPanel" Height="120" Width="300">
<WrapPanel Orientation="Vertical">
<Button>Test button 1</Button>
<Button>Test button 2</Button> Common interface
<Button>Test button 3</Button> controls
<Button Width="140">Test button 4</Button> The Menu control
<Button>Test button 5</Button> The ContextMenu
<Button>Test button 6</Button> The ToolBar control
</WrapPanel> The StatusBar control
</Window> The Ribbon Control
The TabControl
Using the TabControl
Tab positions
Styling the TabItems
Notice how button 5 only uses the width - it doesn't care about the height,
although it causes the sixth button to be pushed to a new column.
List controls
Previous Next The ItemsControl
The ListBox control
The ComboBox control
ListView sorting
How-to: ListView with
column sorting
ListView filtering
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
The StackPanel control
Download this entire
tutorial as PDF right
now!
The StackPanel is very similar to the WrapPanel, but with at least one About WPF
important difference: The StackPanel doesn't wrap the content. Instead it
What is WPF?
stretches it content in one direction, allowing you to stack item after item on
WPF vs. WinForms
top of each other. Let's first try a very simple example, much like we did with
the WrapPanel:
Getting started
<Window x:Class="WpfTutorialSamples.Panels.StackPanel"
Visual Studio Express
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta Hello, WPF!
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" XAML
Title="StackPanel" Height="160" Width="300"> What is XAML?
<StackPanel> Basic XAML
<Button>Button 1</Button> Events in XAML
<Button>Button 2</Button>
<Button>Button 3</Button>
<Button>Button 4</Button>
A WPF application
<Button>Button 5</Button>
Introduction
<Button>Button 6</Button>
The Window
</StackPanel>
Working with App.xaml
</Window>
Command-line parameters
Resources
Handling exceptions
Basic controls
The TextBlock control
The TextBlock control - Inline
formatting
The Label control
The TextBox control
The CheckBox control
The first thing you should notice is how the StackPanel doesn't really care
Data binding
Introduction
Another thing you will likely notice is that the StackPanel stretches its child Hello, bound world!
control by default. On a vertically aligned StackPanel, like the one in the first Using the DataContext
example, all child controls get stretched horizontally. On a horizontally The UpdateSourceTrigger
aligned StackPanel, all child controls get stretched vertically, as seen above. property
The StackPanel does this by setting the HorizontalAlignment or Responding to changes
VerticalAlignment property on its child controls to Stretch, but you can easily Value conversion with
override this if you want to. Have a look at the next example, where we use IValueConverter
the same markup as we did in the previous example, but this time we assign The StringFormat property
values to the VerticalAlignment property for all the child controls: Debugging data bindings
<Window x:Class="WpfTutorialSamples.Panels.StackPanel"
Commands
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta Introduction
Using commands
Implementing custom
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" commands
Title="StackPanel" Height="160" Width="300">
<StackPanel Orientation="Horizontal">
<Button VerticalAlignment="Top">Button
Common interface
1</Button>
controls
<Button VerticalAlignment="Center">Button
The Menu control
2</Button>
The ContextMenu
<Button VerticalAlignment="Bottom">Button
The ToolBar control
3</Button>
The StatusBar control
<Button VerticalAlignment="Bottom">Button
The Ribbon Control
4</Button>
<Button VerticalAlignment="Center">Button
5</Button>
<Button VerticalAlignment="Top">Button Rich Text controls
6</Button> Introduction
</StackPanel> The
</Window> FlowDocumentScrollViewer
control
The
FlowDocumentPageViewer
control
The FlowDocumentReader
control
Creating a FlowDocument
from Code-behind
Advanced FlowDocument
content
The RichTextBox control
We use the Top, Center and Bottom values to place the buttons in a nice
pattern, just for kicks. The same can of course be done for a vertically
aligned StackPanel, where you would use the HorizontalAlignment on the Misc. controls
child controls: The Border control
The Slider control
<Window x:Class="WpfTutorialSamples.Panels.StackPanel" The ProgressBar control
The WebBrowser control
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta The WindowsFormsHost
control
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="StackPanel" Height="160" Width="300"> The TabControl
<StackPanel Orientation="Vertical"> Using the TabControl
<Button HorizontalAlignment="Left">Button Tab positions
1</Button> Styling the TabItems
<Button
HorizontalAlignment="Center">Button 2</Button>
<Button HorizontalAlignment="Right">Button
List controls
3</Button>
The ItemsControl
<Button HorizontalAlignment="Right">Button
The ListBox control
4</Button>
The ComboBox control
<Button
HorizontalAlignment="Center">Button 5</Button>
<Button HorizontalAlignment="Left">Button
6</Button> The ListView control
</StackPanel> Introduction
</Window> A simple ListView
ListView, data binding and
ItemTemplate
ListView with a GridView
How-to: Left aligned column
names
ListView grouping
ListView sorting
How-to: ListView with
column sorting
ListView filtering
As you can see, the controls still go from top to bottom, but instead of having The TreeView control
the same width, each control is aligned to the left, the right or center.
Introduction
A simple TreeView
Previous Next TreeView, data binding and
multiple templates
Handling
Selection/Expansion state
comments powered by Disqus Lazy loading TreeView items
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
The DockPanel control
Download this entire
tutorial as PDF right
now!
The DockPanel makes it easy to dock content in all four directions (top, About WPF
bottom, left and right). This makes it a great choice in many situations, where
What is WPF?
you want to divide the window into specific areas, especially because by
WPF vs. WinForms
default, the last element inside the DockPanel, unless this feature is
specifically disabled, will automatically fill the rest of the space (center).
As we've seen with many of the other panels in WPF, you start taking Getting started
advantage of the panel possibilities by using an attached property of it, in this Visual Studio Express
case the DockPanel.Dock property, which decides in which direction you Hello, WPF!
want the child control to dock to. If you don't use this, the first control(s) will
be docked to the left, with the last one taking up the remaining space. Here's
an example on how you use it:
XAML
What is XAML?
<Window x:Class="WpfTutorialSamples.Panels.DockPanel"
Basic XAML
Events in XAML
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
A WPF application
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="DockPanel" Height="250" Width="250"> Introduction
<DockPanel> The Window
<Button Working with App.xaml
DockPanel.Dock="Left">Left</Button> Command-line parameters
<Button DockPanel.Dock="Top">Top</Button> Resources
<Button Handling exceptions
DockPanel.Dock="Right">Right</Button>
<Button
DockPanel.Dock="Bottom">Bottom</Button> Basic controls
<Button>Center</Button> The TextBlock control
</DockPanel> The TextBlock control - Inline
</Window> formatting
The Label control
The TextBox control
The CheckBox control
Panels
Introduction to WPF Panels
The Canvas
The WrapPanel
The StackPanel
The DockPanel
The Grid
The Grid - Rows & Columns
The Grid - Units
As already mentioned, we don't assign a dock position for the last child,
The Grid - Spanning
because it automatically centers the control, allowing it to fill the remaining
The Grid - GridSplitter
space. You will also notice that the controls around the center only takes up
Using the Grid: A contact
the amount of space that they need - everything else is left for the center
form
position. That is also why you will see the Right button take up a bit more
space than the Left button - the extra character in the text simply requires
more pixels.
Data binding
The last thing that you will likely notice, is how the space is divided. For Introduction
instance, the Top button doesn't get all of the top space, because the Left Hello, bound world!
button takes a part of it. The DockPanel decides which control to favor by Using the DataContext
looking at their position in the markup. In this case, the Left button gets The UpdateSourceTrigger
precedence because it's placed first in the markup. Fortunately, this also property
means that it's very easy to change, as we'll see in the next example, where Responding to changes
we have also evened out the space a bit by assigning widths/heights to the Value conversion with
child controls: IValueConverter
The StringFormat property
<Window x:Class="WpfTutorialSamples.Panels.DockPanel" Debugging data bindings
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
Commands
Introduction
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Using commands
Title="DockPanel" Height="250" Width="250">
Implementing custom
<DockPanel>
commands
<Button DockPanel.Dock="Top"
Height="50">Top</Button>
<Button DockPanel.Dock="Bottom"
Common interface
Height="50">Bottom</Button>
controls
<Button DockPanel.Dock="Left"
Width="50">Left</Button> The Menu control
<Button DockPanel.Dock="Right" The ContextMenu
Width="50">Right</Button> The ToolBar control
<Button>Center</Button> The StatusBar control
</DockPanel> The Ribbon Control
</Window>
column sorting
ListView filtering
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
The Grid Control
Download this entire
tutorial as PDF right
now!
The Grid is probably the most complex of the panel types. A Grid can contain About WPF
multiple rows and columns. You define a height for each of the rows and a
What is WPF?
width for each of the columns, in either an absolute amount of pixels, in a
WPF vs. WinForms
percentage of the available space or as auto, where the row or column will
automatically adjust its size depending on the content. Use the Grid when the
other panels doesn't do the job, e.g. when you need multiple columns and
often in combination with the other panels. Getting started
Visual Studio Express
In its most basic form, the Grid will simply take all of the controls you put into Hello, WPF!
it, stretch them to use the maximum available space and place it on top of
each other:
XAML
<Window x:Class="WpfTutorialSamples.Panels.Grid"
What is XAML?
Basic XAML
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
Events in XAML
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
A WPF application
Title="Grid" Height="300" Width="300">
<Grid> Introduction
<Button>Button 1</Button> The Window
<Button>Button 2</Button> Working with App.xaml
</Grid> Command-line parameters
</Window> Resources
Handling exceptions
Basic controls
The TextBlock control
The TextBlock control - Inline
formatting
The Label control
The TextBox control
The CheckBox control
Commands
Introduction
Using commands
Implementing custom
commands
Common interface
controls
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Misc. controls
Title="Grid" Height="300" Width="300">
The Border control
<Grid>
The Slider control
<Grid.ColumnDefinitions>
The ProgressBar control
<ColumnDefinition Width="*" />
The WebBrowser control
<ColumnDefinition Width="*" />
The WindowsFormsHost
</Grid.ColumnDefinitions>
control
<Button VerticalAlignment="Top"
HorizontalAlignment="Center">Button 1</Button>
<Button Grid.Column="1"
VerticalAlignment="Center" The TabControl
HorizontalAlignment="Right">Button 2</Button> Using the TabControl
</Grid> Tab positions
</Window> Styling the TabItems
List controls
The ItemsControl
The ListBox control
The ComboBox control
ItemTemplate
As you can see from the resulting screenshot, the first button is now placed in ListView with a GridView
the top and centered. The second button is placed in the middle, aligned to How-to: Left aligned column
the right. names
ListView grouping
Previous Next ListView sorting
How-to: ListView with
column sorting
ListView filtering
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
The Grid - Rows & columns
Download this entire
tutorial as PDF right
now!
In the last chapter, we introduced you to the great Grid panel and showed you About WPF
a couple of basic examples on how to use it. In this chapter we will do some
What is WPF?
more advanced layouts, as this is where the Grid really shines. First of all,
WPF vs. WinForms
let's throw in more columns and even some rows, for a true tabular layout:
<Window x:Class="WpfTutorialSamples.Panels.TabularGrid"
Getting started
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta Visual Studio Express
Hello, WPF!
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="TabularGrid" Height="300" Width="300"> XAML
<Grid> What is XAML?
<Grid.ColumnDefinitions> Basic XAML
<ColumnDefinition Width="2*" /> Events in XAML
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
A WPF application
<Grid.RowDefinitions>
Introduction
<RowDefinition Height="2*" />
The Window
<RowDefinition Height="1*" />
Working with App.xaml
<RowDefinition Height="1*" />
Command-line parameters
</Grid.RowDefinitions>
Resources
<Button>Button 1</Button>
Handling exceptions
<Button Grid.Column="1">Button 2</Button>
<Button Grid.Column="2">Button 3</Button>
<Button Grid.Row="1">Button 4</Button>
<Button Grid.Column="1" Basic controls
Grid.Row="1">Button 5</Button> The TextBlock control
<Button Grid.Column="2" The TextBlock control - Inline
Grid.Row="1">Button 6</Button> formatting
<Button Grid.Row="2">Button 7</Button> The Label control
<Button Grid.Column="1" The TextBox control
Grid.Row="2">Button 8</Button> The CheckBox control
Data binding
Introduction
Hello, bound world!
A total of nine buttons, each placed in their own cell in a grid containing three Using the DataContext
rows and three columns. We once again use a star based width, but this time The UpdateSourceTrigger
we assign a number as well - the first row and the first column has a width of property
2*, which basically means that it uses twice the amount of space as the rows Responding to changes
and columns with a width of 1* (or just * - that's the same). Value conversion with
IValueConverter
You will also notice that I use the Attached properties Grid.Row and The StringFormat property
Grid.Column to place the controls in the grid, and once again you will notice Debugging data bindings
that I have omitted these properties on the controls where I want to use either
the first row or the first column (or both). This is essentially the same as
specifying a zero. This saves a bit of typing, but you might prefer to assign
Commands
them anyway for a better overview - that's totally up to you!
Introduction
Using commands
Previous Next
Implementing custom
commands
Introduction
The
FlowDocumentScrollViewer
control
The
FlowDocumentPageViewer
control
The FlowDocumentReader
control
Creating a FlowDocument
from Code-behind
Advanced FlowDocument
content
The RichTextBox control
Misc. controls
The Border control
The Slider control
The ProgressBar control
The WebBrowser control
The WindowsFormsHost
control
The TabControl
Using the TabControl
Tab positions
Styling the TabItems
List controls
The ItemsControl
The ListBox control
The ComboBox control
ListView filtering
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
The Grid - Units
Download this entire
tutorial as PDF right
now!
So far we have mostly used the star width/height, which specifies that a row About WPF
or a column should take up a certain percentage of the combined space.
What is WPF?
However, there are two other ways of specifying the width or height of a
WPF vs. WinForms
column or a row: Absolute units and the Auto width/height. Let's try creating a
Grid where we mix these:
Getting started
<Window x:Class="WpfTutorialSamples.Panels.GridUnits"
Visual Studio Express
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta Hello, WPF!
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" XAML
Title="GridUnits" Height="200" Width="400"> What is XAML?
<Grid> Basic XAML
<Grid.ColumnDefinitions> Events in XAML
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="100" />
A WPF application
</Grid.ColumnDefinitions>
Introduction
<Button>Button 1</Button>
The Window
<Button Grid.Column="1">Button 2 with long
Working with App.xaml
text</Button>
Command-line parameters
<Button Grid.Column="2">Button 3</Button>
Resources
</Grid>
Handling exceptions
</Window>
Basic controls
The TextBlock control
The TextBlock control - Inline
formatting
The Label control
The TextBox control
The CheckBox control
In this example, the first button has a star width, the second one has its width Panels
set to Auto and the last one has a static width of 100 pixels. Introduction to WPF Panels
The Canvas
The result can be seen on the screenshot, where the second button only The WrapPanel
takes exactly the amount of space it needs to render its longer text, the third The StackPanel
button takes exactly the 100 pixels it was promised and the first button, with The DockPanel
the variable width, takes the rest. The Grid
The Grid - Rows & Columns
In a Grid where one or several columns (or rows) have a variable (star) width,
The Grid - Units
they automatically get to share the width/height not already used by the
The Grid - Spanning
columns/rows which uses an absolute or Auto width/height. This becomes
The Grid - GridSplitter
more obvious when we resize the window:
Using the Grid: A contact
form
Data binding
Introduction
Hello, bound world!
Using the DataContext
The UpdateSourceTrigger
property
Responding to changes
Value conversion with
IValueConverter
The StringFormat property
Debugging data bindings
Commands
Introduction
Using commands
Implementing custom
On the first screenshot, you will see that the Grid reserves the space for the commands
last two buttons, even though it means that the first one doesn't get all the
space it needs to render properly. On the second screenshot, you will see the
last two buttons keeping the exact same amount of space, leaving the Common interface
surplus space to the first button. controls
The Menu control
This can be a very useful technique when designing a wide range of dialogs.
The ContextMenu
For instance, consider a simple contact form where the user enters a name, The ToolBar control
an e-mail address and a comment. The first two fields will usually have a The StatusBar control
fixed height, while the last one might as well take up as much space as The Ribbon Control
possible, leaving room to type a longer comment. In the next chapter, we will
try building a contact form, using the grid and rows and columns of different
heights and widths.
Rich Text controls
Introduction
Previous Next
The
FlowDocumentScrollViewer
control
The
comments powered by Disqus FlowDocumentPageViewer
control
The FlowDocumentReader
control
Creating a FlowDocument
from Code-behind
Advanced FlowDocument
content
The RichTextBox control
Misc. controls
The Border control
The Slider control
The ProgressBar control
The WebBrowser control
The WindowsFormsHost
control
The TabControl
Using the TabControl
Tab positions
Styling the TabItems
List controls
The ItemsControl
The ListBox control
The ComboBox control
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
The Grid - Spanning
Download this entire
tutorial as PDF right
now!
The default Grid behavior is that each control takes up one cell, but About WPF
sometimes you want a certain control to take up more rows or columns.
What is WPF?
Fortunately the Grid makes this very easy, with the Attached properties
WPF vs. WinForms
ColumnSpan and RowSpan. The default value for this property is obviously
1, but you can specify a bigger number to make the control span more rows
or columns.
Getting started
Here's a very simple example, where we use the ColumnSpan property: Visual Studio Express
Hello, WPF!
<Window x:Class="WpfTutorialSamples.Panels.GridColRowSpan"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta XAML
What is XAML?
Basic XAML
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Events in XAML
Title="GridColRowSpan" Height="110" Width="300">
<Grid>
<Grid.ColumnDefinitions>
A WPF application
<ColumnDefinition Width="1*" /> Introduction
<ColumnDefinition Width="1*" /> The Window
</Grid.ColumnDefinitions> Working with App.xaml
<Grid.RowDefinitions> Command-line parameters
<RowDefinition Height="*" /> Resources
<RowDefinition Height="*" /> Handling exceptions
</Grid.RowDefinitions>
<Button>Button 1</Button>
<Button Grid.Column="1">Button 2</Button> Basic controls
<Button Grid.Row="1" The TextBlock control
Grid.ColumnSpan="2">Button 3</Button> The TextBlock control - Inline
</Grid> formatting
</Window> The Label control
The TextBox control
The CheckBox control
Panels
Introduction to WPF Panels
We just define two columns and two rows, all of them taking up their equal The Canvas
share of the place. The first two buttons just use the columns normally, but The WrapPanel
with the third button, we make it take up two columns of space on the second The StackPanel
row, using the ColumnSpan attribute. The DockPanel
The Grid
This is all so simple that we could have just used a combination of panels to The Grid - Rows & Columns
achieve the same effect, but for just slightly more advanced cases, this is The Grid - Units
really useful. Let's try something which better shows how powerful this is: The Grid - Spanning
The Grid - GridSplitter
<Window Using the Grid: A contact
x:Class="WpfTutorialSamples.Panels.GridColRowSpanAdvanced" form
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
Data binding
Introduction
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Hello, bound world!
Title="GridColRowSpanAdvanced" Height="300"
Using the DataContext
Width="300">
The UpdateSourceTrigger
<Grid>
property
<Grid.ColumnDefinitions>
Responding to changes
<ColumnDefinition Width="*" />
Value conversion with
<ColumnDefinition Width="*" />
IValueConverter
<ColumnDefinition Width="*" />
The StringFormat property
</Grid.ColumnDefinitions>
Debugging data bindings
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
Commands
<RowDefinition Height="*" />
</Grid.RowDefinitions> Introduction
<Button Grid.ColumnSpan="2">Button Using commands
1</Button> Implementing custom
<Button Grid.Column="3">Button 2</Button> commands
<Button Grid.Row="1">Button 3</Button>
<Button Grid.Column="1" Grid.Row="1"
Grid.RowSpan="2" Grid.ColumnSpan="2">Button 4</Button> Common interface
<Button Grid.Column="0" controls
Grid.Row="2">Button 5</Button> The Menu control
</Grid> The ContextMenu
</Window> The ToolBar control
The StatusBar control
The Ribbon Control
Introduction
The
FlowDocumentScrollViewer
control
The
FlowDocumentPageViewer
control
The FlowDocumentReader
control
Creating a FlowDocument
from Code-behind
Advanced FlowDocument
content
With three columns and three rows we would normally have nine cells, but in The RichTextBox control
this example, we use a combination of row and column spanning to fill all the
available space with just five buttons. As you can see, a control can span
either extra columns, extra rows or in the case of button 4: both. Misc. controls
The Border control
So as you can see, spanning multiple columns and/or rows in a Grid is very
The Slider control
easy. In a later article, we will use the spanning, along with all the other Grid
The ProgressBar control
techniques in a more practical example.
The WebBrowser control
The WindowsFormsHost
Previous Next control
The TabControl
comments powered by Disqus Using the TabControl
Tab positions
Styling the TabItems
List controls
The ItemsControl
The ListBox control
The ComboBox control
ListView sorting
How-to: ListView with
column sorting
ListView filtering
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
The GridSplitter
Download this entire
tutorial as PDF right
now!
As you saw in the previous articles, the Grid panel makes it very easy to About WPF
divide up the available space into individual cells. Using column and row
What is WPF?
definitions, you can easily decide how much space each row or column
WPF vs. WinForms
should take up, but what if you want to allow the user to change this? This is
where
the GridSplitter control comes into play.
The GridSplitter is used simply by adding it to a column or a row in a Grid, Getting started
with the proper amount of space for it, e.g. 5 pixels. It will then allow the
user Visual Studio Express
to drag it from side to side or up and down, while changing the size of the Hello, WPF!
column or row on each of the sides of it. Here's an example:
<Window XAML
x:Class="WpfTutorialSamples.Panels.GridSplitterSample"
What is XAML?
Basic XAML
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
Events in XAML
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
A WPF application
Title="GridSplitterSample" Height="300"
Width="300"> Introduction
<Grid> The Window
<Grid.ColumnDefinitions> Working with App.xaml
<ColumnDefinition Width="*" /> Command-line parameters
<ColumnDefinition Width="5" /> Resources
<ColumnDefinition Width="*" /> Handling exceptions
</Grid.ColumnDefinitions>
<TextBlock FontSize="55"
HorizontalAlignment="Center" VerticalAlignment="Center" Basic controls
TextWrapping="Wrap">Left side</TextBlock> The TextBlock control
<GridSplitter Grid.Column="1" Width="5" The TextBlock control - Inline
HorizontalAlignment="Stretch" /> formatting
<TextBlock Grid.Column="2" FontSize="55" The Label control
HorizontalAlignment="Center" VerticalAlignment="Center" The TextBox control
TextWrapping="Wrap">Right side</TextBlock> The CheckBox control
</Grid>
Panels
Introduction to WPF Panels
The Canvas
The WrapPanel
The StackPanel
The DockPanel
The Grid
The Grid - Rows & Columns
The Grid - Units
The Grid - Spanning
The Grid - GridSplitter
Using the Grid: A contact
form
Data binding
Introduction
Hello, bound world!
Using the DataContext
The UpdateSourceTrigger
property
Responding to changes
Value conversion with
IValueConverter
The StringFormat property
Debugging data bindings
Commands
Introduction
Using commands
Implementing custom
As you can see, I've simply created a Grid with two equally wide columns, commands
with a 5 pixel column in the middle. Each of the sides are just a TextBlock
control to illustrate the point. As you can see from the screenshots, the
GridSplitter is rendered as a dividing line between the two columns and as Common interface
soon
as the mouse is over it, the cursor is changed to reflect that it can be controls
resized.
The Menu control
Horizontal GridSplitter The ContextMenu
The ToolBar control
The GridSplitter is very easy to use and of course it supports horizontal splits The StatusBar control
as well. In fact, you hardly have to change anything to make it work The Ribbon Control
horizontally instead of vertically, as the next example will show:
x:Class="WpfTutorialSamples.Panels.GridSplitterHorizontalSam Introduction
The
FlowDocumentScrollViewer
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta control
The
FlowDocumentPageViewer
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" control
Title="GridSplitterHorizontalSample" Height="300" The FlowDocumentReader
Width="300"> control
<Grid> Creating a FlowDocument
<Grid.RowDefinitions> from Code-behind
<RowDefinition Height="*" /> Advanced FlowDocument
<RowDefinition Height="5" /> content
<RowDefinition Height="*" /> The RichTextBox control
</Grid.RowDefinitions>
<TextBlock FontSize="55"
HorizontalAlignment="Center" VerticalAlignment="Center"
Misc. controls
TextWrapping="Wrap">Top</TextBlock>
The Border control
<GridSplitter Grid.Row="1" Height="5"
The Slider control
HorizontalAlignment="Stretch" />
The ProgressBar control
<TextBlock Grid.Row="2" FontSize="55"
The WebBrowser control
HorizontalAlignment="Center" VerticalAlignment="Center"
The WindowsFormsHost
TextWrapping="Wrap">Bottom</TextBlock>
control
</Grid>
</Window>
The TabControl
Using the TabControl
Tab positions
Styling the TabItems
List controls
The ItemsControl
The ListBox control
The ComboBox control
As you can see, I simply changed the columns into rows and on the The ListView control
GridSplitter, I defined a Height instead of a Width. The GridSplitter figures out
Introduction
the
rest on its own, but in case it doesn't, you can use the ResizeDirection
A simple ListView
property on it to force it into either Rows or Columns mode.
ListView, data binding and
ItemTemplate
Previous Next ListView with a GridView
How-to: Left aligned column
names
ListView grouping
comments powered by Disqus ListView sorting
How-to: ListView with
column sorting
ListView filtering
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
Using the Grid: A contact form
Download this entire
tutorial as PDF right
now!
In the last couple of chapters we went through a lot of theoretic information, About WPF
each with some very theoretic examples. In this chapter we will combine
What is WPF?
what we have learned about the Grid so far, into an example that can be
WPF vs. WinForms
used in the real world: A simple contact form.
The good thing about the contact form is that it's just an example of a
commonly used dialog - you can take the techniques used and apply them to Getting started
almost any type of dialog that you need to create. Visual Studio Express
Hello, WPF!
The first take on this task is very simple and will show you a very basic
contact form. It uses three rows, two of them with Auto heights and the last
one with star height, so it consumes the rest of the available space:
XAML
What is XAML?
<Window
Basic XAML
x:Class="WpfTutorialSamples.Panels.GridContactForm"
Events in XAML
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
A WPF application
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Introduction
Title="GridContactForm" Height="300" Width="300"> The Window
<Grid> Working with App.xaml
<Grid.RowDefinitions> Command-line parameters
<RowDefinition Height="Auto" /> Resources
<RowDefinition Height="Auto" /> Handling exceptions
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBox>Name</TextBox> Basic controls
<TextBox Grid.Row="1">E-mail</TextBox>
The TextBlock control
<TextBox Grid.Row="2"
The TextBlock control - Inline
AcceptsReturn="True">Comment</TextBox>
formatting
</Grid>
The Label control
</Window>
The TextBox control
The CheckBox control
Panels
Introduction to WPF Panels
The Canvas
The WrapPanel
The StackPanel
The DockPanel
The Grid
As you can see, the last TextBox simply takes up the remaining space, while
The Grid - Rows & Columns
the first two only takes up the space they require. Try resizing the window
The Grid - Units
and you will see the comment TextBox resize with it.
The Grid - Spanning
In this very simple example, there are no labels to designate what each of the The Grid - GridSplitter
fields are for. Instead, the explanatory text is inside the TextBox, but this is Using the Grid: A contact
not generally how a Windows dialog looks. Let's try improving the look and form
usability a bit:
Introduction
The
FlowDocumentScrollViewer
control
The
FlowDocumentPageViewer
control
The FlowDocumentReader
control
Creating a FlowDocument
from Code-behind
Advanced FlowDocument
content
The RichTextBox control
But perhaps you're in a situation where the comment field is pretty self-
explanatory? In that case, let's skip the label and use ColumnSpan to get
even more space for the comment TextBox:
Misc. controls
The Border control
<TextBox Grid.ColumnSpan="2" Grid.Row="2" The Slider control
AcceptsReturn="True" /> The ProgressBar control
The WebBrowser control
The WindowsFormsHost
control
The TabControl
Using the TabControl
Tab positions
Styling the TabItems
List controls
The ItemsControl
The ListBox control
The ComboBox control
So as you can see, the Grid is a very powerful panel. Hopefully you can use The ListView control
all of these techniques when designing your own dialogs. Introduction
A simple ListView
Previous Next ListView, data binding and
ItemTemplate
ListView with a GridView
How-to: Left aligned column
names
comments powered by Disqus
ListView grouping
ListView sorting
How-to: ListView with
column sorting
ListView filtering
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
Introduction to WPF data binding
Download this entire
tutorial as PDF right
now!
Wikipedia describes the concept of data binding very well: About WPF
Data binding is general technique that binds two data/information sources What is WPF?
together and maintains synchronization of data. WPF vs. WinForms
With WPF, Microsoft has put data binding in the front seat and once you start
learning WPF, you will realize that it's an important aspect of pretty much Getting started
everything you do. If you come from the world of WinForms, then the huge
Visual Studio Express
focus on data binding might scare you a bit, but once you get used to it, you
Hello, WPF!
will
likely come to love it, as it makes a lot of things cleaner and easier to
maintain.
Data binding in WPF is the preferred way to bring data from your code to the XAML
UI layer. Sure, you can set properties on a control manually or you can What is XAML?
populate a ListBox by adding items to it from a loop, but the cleanest and Basic XAML
purest WPF way is to add a binding between the source and the destination Events in XAML
UI
element.
Summary A WPF application
In the next chapter, we'll look into a simple example where data binding is Introduction
used and after that, we'll talk some more about all the possibilities. The The Window
concept of data binding is included pretty early in this tutorial, because it's Working with App.xaml
such an integral part of using WPF, which you will see once you explore the Command-line parameters
rest of the chapters, where it's used almost all of the time. Resources
Handling exceptions
However, the more theoretical part of data binding might be too heavy if you
just want to get started building a simple WPF application. In that case I
suggest that you have a look at the "Hello, bound world!" article to get a Basic controls
glimpse of how data binding works, and then save the rest of the data binding
The TextBlock control
articles for later, when you're ready to get some more theory.
The TextBlock control - Inline
formatting
Previous Next The Label control
The TextBox control
The CheckBox control
Panels
Introduction to WPF Panels
The Canvas
The WrapPanel
The StackPanel
The DockPanel
The Grid
The Grid - Rows & Columns
The Grid - Units
The Grid - Spanning
The Grid - GridSplitter
Using the Grid: A contact
form
Data binding
Introduction
Hello, bound world!
Using the DataContext
The UpdateSourceTrigger
property
Responding to changes
Value conversion with
IValueConverter
The StringFormat property
Debugging data bindings
Commands
Introduction
Using commands
Implementing custom
commands
Common interface
controls
The Menu control
The ContextMenu
The ToolBar control
The StatusBar control
The Ribbon Control
Introduction
The
FlowDocumentScrollViewer
control
The
FlowDocumentPageViewer
control
The FlowDocumentReader
control
Creating a FlowDocument
from Code-behind
Advanced FlowDocument
content
The RichTextBox control
Misc. controls
The Border control
The Slider control
The ProgressBar control
The WebBrowser control
The WindowsFormsHost
control
The TabControl
Using the TabControl
Tab positions
Styling the TabItems
List controls
The ItemsControl
The ListBox control
The ComboBox control
ListView filtering
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
Hello, bound world!
Download this entire
tutorial as PDF right
now!
Just like we started this tutorial with the classic "Hello, world!" example, we'll About WPF
show you how easy it is to use data binding in WPF with a "Hello, bound
What is WPF?
world!" example. Let's jump straight into it and then I'll explain it afterwards:
WPF vs. WinForms
<Window
x:Class="WpfTutorialSamples.DataBinding.HelloBoundWorldSampl
Getting started
Visual Studio Express
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta Hello, WPF!
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" XAML
Title="HelloBoundWorldSample" Height="110" What is XAML?
Width="280"> Basic XAML
<StackPanel Margin="10"> Events in XAML
<TextBox Name="txtValue" />
<WrapPanel Margin="0,10">
<TextBlock Text="Value: "
A WPF application
FontWeight="Bold" />
Introduction
<TextBlock Text="{Binding
The Window
Path=Text, ElementName=txtValue}" />
Working with App.xaml
</WrapPanel>
Command-line parameters
</StackPanel>
Resources
</Window>
Handling exceptions
Basic controls
The TextBlock control
The TextBlock control - Inline
formatting
The Label control
The TextBox control
This simple example shows how we bind the value of the TextBlock to match The CheckBox control
the Text property of the TextBox. As you can see from the screenshot, the
{Binding Path=NameOfProperty}
Data binding
The Path notes the property that you want to bind to, however, since Path is
Introduction
the default property of a binding, you may leave it out if you want to, like
this:
Hello, bound world!
Using the DataContext
{Binding NameOfProperty}
The UpdateSourceTrigger
You will see many different examples, some of them where Path is explicitly property
defined and some where it's left out. In the end it's really up to you though. Responding to changes
Value conversion with
A binding has many other properties though, one of them being the IValueConverter
ElementName which we use in our example. This allows us to connect The StringFormat property
directly to another UI
element as the source. Each property that we set in the Debugging data bindings
binding is separated by a comma:
{Binding Path=Text, ElementName=txtValue}
Commands
Summary Introduction
Using commands
This was just a glimpse of all the binding possibilities of WPF. In the next Implementing custom
chapters, we'll discover more of them, to show you just how powerful data commands
binding is.
Introduction
The
FlowDocumentScrollViewer
control
The
FlowDocumentPageViewer
control
The FlowDocumentReader
control
Creating a FlowDocument
from Code-behind
Advanced FlowDocument
content
The RichTextBox control
Misc. controls
The Border control
The Slider control
The ProgressBar control
The WebBrowser control
The WindowsFormsHost
control
The TabControl
Using the TabControl
Tab positions
Styling the TabItems
List controls
The ItemsControl
The ListBox control
The ComboBox control
ListView filtering
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
Using the DataContext
Download this entire
tutorial as PDF right
now!
The DataContext property is the default source of your bindings, unless you About WPF
specifically declare another source, like we did in the previous chapter with
What is WPF?
the ElementName property. It's defined on the FrameworkElement class,
WPF vs. WinForms
which most UI controls, including the WPF Window, inherits from. Simply put,
it
allows you to specify a basis for your bindings
There's no default source for the DataContext property (it's simply null from Getting started
the start), but since a DataContext is inherited down through the control Visual Studio Express
hierarchy, you can set a DataContext for the Window itself and then use it Hello, WPF!
throughout all of the child controls. Let's try illustrating that with a simple
example:
XAML
<Window
What is XAML?
x:Class="WpfTutorialSamples.DataBinding.DataContextSample"
Basic XAML
Events in XAML
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
A WPF application
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="DataContextSample" Height="130" Introduction
Width="280"> The Window
<StackPanel Margin="15"> Working with App.xaml
<WrapPanel> Command-line parameters
<TextBlock Text="Window title: " Resources
/> Handling exceptions
<TextBox Text="{Binding Title,
UpdateSourceTrigger=PropertyChanged}" Width="150" />
</WrapPanel> Basic controls
<WrapPanel Margin="0,10,0,0"> The TextBlock control
<TextBlock Text="Window The TextBlock control - Inline
dimensions: " /> formatting
<TextBox Text="{Binding Width}" The Label control
Width="50" /> The TextBox control
<TextBlock Text=" x " /> The CheckBox control
<TextBox Text="{Binding Height}"
The Code-behind for this example only adds one line of interesting code:
After the standard InitalizeComponent() call, we assign the "this" reference to
the DataContext, which basically just tells the Window that we want itself to Commands
be the data context. Introduction
Using commands
In the XAML, we use this fact to bind to several of the Window properties, Implementing custom
including Title, Width and Height. Since the window has a DataContext, commands
which is
passed down to the child controls, we don't have to define a source
on each of the bindings - we just use the values as if they were globally
available. Common interface
controls
Try running the example and resize the window - you will see that the
dimension changes are immediately reflected in the textboxes. You can also The Menu control
try
writing a different title in the first textbox, but you might be surprised to The ContextMenu
see that this change is not reflected immediately. Instead, you have to move The ToolBar control
the focus to another control before the change is applied. Why? Well, that's The StatusBar control
the subject for the next chapter. The Ribbon Control
Summary
Rich Text controls
Using the DataContext property is like setting the basis of all bindings down
Introduction
through the hierarchy of controls. This saves you the hassle of manually
The
defining a source for each binding, and once you really start using data
FlowDocumentScrollViewer
bindings, you will definitely appreciate the time and typing saved.
control
However, this doesn't mean that you have to use the same DataContext for The
all controls within a Window. Since each control has its own DataContext FlowDocumentPageViewer
property,
you can easily break the chain of inheritance and override the control
DataContext with a new value. This allows you to do stuff like having a global The FlowDocumentReader
DataContext
on the window and then a more local and specific DataContext control
on e.g. a panel holding a separate form or something along those lines. Creating a FlowDocument
from Code-behind
Advanced FlowDocument
Previous Next
content
The RichTextBox control
The TabControl
Using the TabControl
Tab positions
Styling the TabItems
List controls
The ItemsControl
The ListBox control
The ComboBox control
ListView filtering
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
The UpdateSourceTrigger property
Download this entire
tutorial as PDF right
now!
In the previous article we saw how changes in a TextBox was not About WPF
immediately sent back to the source. Instead, the source was updated only
What is WPF?
after focus was
lost on the TextBox. This behavior is controlled by a property
WPF vs. WinForms
on the binding called UpdateSourceTrigger. It defaults to the value
"Default", which basically means that the source is updated based on the
property that you bind to. As of writing, all properties except for the Text
property, is updated as soon as the property changes (PropertyChanged), Getting started
while the Text property is updated when focus on the destination element is Visual Studio Express
lost
(LostFocus). Hello, WPF!
Default is, obviously, the default value of the UpdateSourceTrigger. The other
options are PropertyChanged, LostFocus and Explicit. The first two has
XAML
already been described, while the last one simply means that the update has
What is XAML?
to be pushed manually through to
occur, using a call to UpdateSource on the
Basic XAML
Binding.
Events in XAML
To see how all of these options work, I have updated the example from the
previous chapter to show you all of them:
A WPF application
<Window Introduction
x:Class="WpfTutorialSamples.DataBinding.DataContextSample" The Window
Working with App.xaml
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta Command-line parameters
Resources
Handling exceptions
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="DataContextSample" Height="130"
Width="310"> Basic controls
<StackPanel Margin="15">
The TextBlock control
<WrapPanel>
The TextBlock control - Inline
<TextBlock Text="Window title: "
formatting
/>
The Label control
<TextBox Name="txtWindowTitle"
The TextBox control
Text="{Binding Title, UpdateSourceTrigger=Explicit}"
The CheckBox control
Width="150" />
using System;
using System.Windows;
Data binding
using System.Windows.Controls;
using System.Windows.Data; Introduction
Hello, bound world!
namespace WpfTutorialSamples.DataBinding Using the DataContext
{ The UpdateSourceTrigger
public partial class DataContextSample : Window property
{ Responding to changes
public DataContextSample() Value conversion with
{ IValueConverter
InitializeComponent(); The StringFormat property
this.DataContext = this; Debugging data bindings
}
Introduction
As you can see, each of the three textboxes now uses a different The
UpdateSourceTrigger. FlowDocumentScrollViewer
control
The first one is set to Explicit, which basically means that the source won't The
be updated unless you manually do it. For that reason, I
have added a button FlowDocumentPageViewer
next to the TextBox, which will update the source value on demand. In the control
Code-behind, you will find the Click handler, where we use a
couple of lines The FlowDocumentReader
of code to get the binding from the destination control and then call the control
UpdateSource() method on it. Creating a FlowDocument
from Code-behind
The second TextBox uses the LostFocus value, which is actually the default
Advanced FlowDocument
for a Text binding. It means that the source value will be
updated each time
content
the destination control loses focus.
The RichTextBox control
The third and last TextBox uses the PropertyChanged value, which means
that the source value will be updated each time the bound property
changes,
which it does in this case as soon as the text changes. Misc. controls
The Border control
Try running the example on your own machine and see how the three The Slider control
textboxes act completely different: The first value doesn't update before you The ProgressBar control
click the
button, the second value isn't updated until you leave the TextBox, The WebBrowser control
while the third value updates automatically on each keystroke, text change The WindowsFormsHost
etc. control
Summary
The UpdateSourceTrigger property of a binding controls how and when a The TabControl
changed value is sent back to the source. However, since WPF is pretty Using the TabControl
good at
controlling this for you, the default value should suffice for most Tab positions
cases, where you will get the best mix of a constantly updated UI and good Styling the TabItems
performance.
For those situations where you need more control of the process, this
List controls
property will definitely help though. Just make sure that you don't update the
source
value more often than you actually need to. If you want the full The ItemsControl
control, you can use the Explicit value and then do the updates manually, The ListBox control
but this does take a bit of the fun out of working with data bindings. The ComboBox control
Previous Next
The ListView control
Introduction
A simple ListView
ListView, data binding and
comments powered by Disqus
ItemTemplate
ListView with a GridView
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
Responding to changes
Download this entire
tutorial as PDF right
now!
So far in this tutorial, we have mostly created bindings between UI elements About WPF
and existing classes, but in real life applications, you will obviously be
binding
What is WPF?
to your own data objects. This is just as easy, but once you start doing it, you
WPF vs. WinForms
might discover something that disappoints you: Changes are not
automatically reflected, like they were in previous examples. As you will learn
in this article, you need just a bit of extra work for this to happen, but
fortunately, WPF makes this pretty easy. Getting started
Visual Studio Express
Responding to data source changes Hello, WPF!
There are two different scenarios that you may or may not want to handle
when dealing with data source changes: Changes to the list of items and
XAML
changes in
the bound properties in each of the data objects. How to handle
them may vary, depending on what you're doing and what you're looking to What is XAML?
accomplish, but
WPF comes with two very easy solutions that you can use: Basic XAML
The ObservableCollection and the INotifyPropertyChanged
interface. Events in XAML
The following example will show you why we need these two things:
A WPF application
<Window Introduction
x:Class="WpfTutorialSamples.DataBinding.ChangeNotificationSa The Window
Working with App.xaml
Command-line parameters
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta Resources
Handling exceptions
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ChangeNotificationSample" Height="150"
Basic controls
Width="300">
<DockPanel Margin="10"> The TextBlock control
<StackPanel DockPanel.Dock="Right" The TextBlock control - Inline
Margin="10,0,0,0"> formatting
<Button Name="btnAddUser" The Label control
Click="btnAddUser_Click">Add user</Button> The TextBox control
<Button Name="btnChangeUser" The CheckBox control
Misc. controls
The Border control
The Slider control
The ProgressBar control
The WebBrowser control
The WindowsFormsHost
control
Try running it for yourself and watch how even though you add something to
the list or change the name of one of the users, nothing in the UI is
updated. The example is pretty simple, with a User class that will keep the
The TabControl
name of the user, a ListBox to show them
in and some buttons to manipulate
both the list and its contents. The ItemsSource of the list is assigned to a Using the TabControl
quick list of a couple of users that we
create in the window constructor. The Tab positions
problem is that none of the buttons seems to work. Let's fix that, in two easy Styling the TabItems
steps.
Reflecting changes in the list data source List controls
The ItemsControl
The first step is to get the UI to respond to changes in the list source
The ListBox control
(ItemsSource), like when we add or delete a user. What we need is a list that
The ComboBox control
notifies any destinations of changes to its content, and fortunately, WPF
provides a type of list that will do just that. It's called ObservableCollection,
and you use it much like a regular List<T>, with only a few differences.
The ListView control
In the final example, which you will find below, we have simply replaced the Introduction
List<User> with an ObservableCollection<User> - that's all it
takes! This will A simple ListView
make the Add and Delete button work, but it won't do anything for the ListView, data binding and
"Change name" button, because the change will happen on the bound
data ItemTemplate
object itself and not the source list - the second step will handle that scenario ListView with a GridView
though. How-to: Left aligned column
names
Reflecting changes in the data objects ListView grouping
The second step is to let our custom User class implement the ListView sorting
INotifyPropertyChanged interface. By doing that, our User objects are How-to: ListView with
capable of alerting the
UI layer of changes to its properties. This is a bit more column sorting
cumbersome than just changing the list type, like we did above, but it's still ListView filtering
one of the
simplest way to accomplish these automatic updates.
The final and working example The TreeView control
Introduction
With the two changes described above, we now have an example that WILL
A simple TreeView
reflect changes in the data source. It looks like this:
TreeView, data binding and
multiple templates
<Window Handling
x:Class="WpfTutorialSamples.DataBinding.ChangeNotificationSa
Selection/Expansion state
Lazy loading TreeView items
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
namespace WpfTutorialSamples.DataBinding
{
public partial class ChangeNotificationSample :
Window
{
private ObservableCollection<User> users =
new ObservableCollection<User>();
public ChangeNotificationSample()
{
InitializeComponent();
lbUsers.ItemsSource = users;
}
Summary
As you can see, implementing INotifyPropertyChanged is pretty easy, but it
does create a bit of extra code on your classes, and adds a bit of extra logic
to your properties. This is the price you will have to pay if you want to bind to
your own classes and have the changes reflected in the UI immediately.
Obviously you only have to call NotifyPropertyChanged in the setter's of the
properties that you bind to - the rest can remain the way they are.
The ObservableCollection on the other hand is very easy to deal with - it
simply requires you to use this specific list type in those situations where you
want changes to the source list reflected in a binding destination.
Previous Next
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
Value conversion with IValueConverter
Download this entire
tutorial as PDF right
now!
So far we have used some simple data bindings, where the sending and About WPF
receiving property was always compatible. However, you will soon run into
What is WPF?
situations
where you want to use a bound value of one type and then present
WPF vs. WinForms
it slightly differently.
When to use a value converter
Getting started
Value converters are very frequently used with data bindings. Here are some
Visual Studio Express
basic examples:
Hello, WPF!
You have a numeric value but you want to show zero values in one
way and positive numbers in another way
You want to check a CheckBox based on a value, but the value is a XAML
string like "yes" or "no" instead of a Boolean value What is XAML?
You have a file size in bytes but you wish to show it as bytes, kilobytes, Basic XAML
megabytes or gigabytes based on how big it is Events in XAML
These are some of the simple cases, but there are many more. For instance,
you may want to check a checkbox based on a Boolean value, but you want
A WPF application
it
reversed, so that the CheckBox is checked if the value is false and not
checked if the value is true. You can even use a converter to generate an Introduction
image for
an ImageSource, based on the value, like a green sign for true or a The Window
red sign for false - the possibilities are pretty much endless! Working with App.xaml
Command-line parameters
For cases like this, you can use a value converter. These small classes, Resources
which implement the IValueConverter interface, will act like middlemen and Handling exceptions
translate a value between the source and the destination. So, in any situation
where you need to transform a value before it reaches its destination or
back
to its source again, you likely need a converter. Basic controls
The TextBlock control
Implementing a simple value converter The TextBlock control - Inline
As mentioned, a WPF value converter needs to implement the formatting
IValueConverter interface, or alternatively, the IMultiValueConverter interface The Label control
(more about that
one later). Both interfaces just requires you to implement The TextBox control
two methods: Convert() and ConvertBack(). As the name implies, these The CheckBox control
Let's implement a simple converter which takes a string as input and then
returns a Boolean value, as well as the other way around. If you're new to Panels
WPF,
and you likely are since you're reading this tutorial, then you might not
Introduction to WPF Panels
know all of the concepts used in the example, but don't worry, they will all be
The Canvas
explained after the code listings:
The WrapPanel
The StackPanel
<Window The DockPanel
x:Class="WpfTutorialSamples.DataBinding.ConverterSample" The Grid
The Grid - Rows & Columns
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta The Grid - Units
The Grid - Spanning
The Grid - GridSplitter
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Using the Grid: A contact
xmlns:local="clr- form
namespace:WpfTutorialSamples.DataBinding"
Title="ConverterSample" Height="140" Width="250">
<Window.Resources>
Data binding
<local:YesNoToBooleanConverter
Introduction
x:Key="YesNoToBooleanConverter" />
Hello, bound world!
</Window.Resources>
Using the DataContext
<StackPanel Margin="10">
The UpdateSourceTrigger
<TextBox Name="txtValue" />
property
<WrapPanel Margin="0,10">
Responding to changes
<TextBlock Text="Current value is:
Value conversion with
" />
IValueConverter
<TextBlock Text="{Binding
The StringFormat property
ElementName=txtValue, Path=Text, Converter={StaticResource
Debugging data bindings
YesNoToBooleanConverter}}"></TextBlock>
</WrapPanel>
<CheckBox IsChecked="{Binding
ElementName=txtValue, Path=Text, Converter={StaticResource Commands
YesNoToBooleanConverter}}" Content="Yes" /> Introduction
</StackPanel> Using commands
</Window> Implementing custom
commands
using System;
Common interface
using System.Windows;
controls
using System.Windows.Data;
The Menu control
namespace WpfTutorialSamples.DataBinding The ContextMenu
{ The ToolBar control
public partial class ConverterSample : Window The StatusBar control
{ The Ribbon Control
public ConverterSample()
{
InitializeComponent(); Rich Text controls
} Introduction
} The
FlowDocumentScrollViewer
public class YesNoToBooleanConverter : control
IValueConverter The
{ FlowDocumentPageViewer
public object Convert(object value, Type control
targetType, object parameter, The FlowDocumentReader
System.Globalization.CultureInfo culture) control
{ Creating a FlowDocument
switch(value.ToString().ToLower()) from Code-behind
{ Advanced FlowDocument
case "yes": content
case "oui": The RichTextBox control
return true;
case "no":
case "non":
Misc. controls
return false;
The Border control
}
The Slider control
return false;
The ProgressBar control
}
The WebBrowser control
The WindowsFormsHost
public object ConvertBack(object value,
control
Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
if(value is bool) The TabControl
{ Using the TabControl
if((bool)value == true) Tab positions
return "yes"; Styling the TabItems
else
return "no";
} List controls
return "no";
The ItemsControl
}
The ListBox control
}
The ComboBox control
}
ListView filtering
Code-behind
The DataGrid control
So, let's start from the back and then work our way through the example. We
have implemented a converter in the Code-behind file called Introduction
YesNoToBooleanConverter. As advertised, it just implements the two Custom columns
required methods, called Convert() and ConvertBack(). The Convert() Details row
methods assumes that
it receives a string as the input (the value parameter)
and then converts it to a Boolean true or false value, with a fallback value of
false. For
fun, I added the possibility to do this conversion from French words Styles
as well. Introduction
Using styles
The ConvertBack() method obviously does the opposite: It assumes an input Triggers
value with a Boolean type and then returns the English word "yes" or "no" in Multi triggers
return, with a fallback value of "no". Trigger animations
You may wonder about the additional parameters that these two methods
take, but they're not needed in this example. We'll use them in one of the
next
chapters, where they will be explained. Misc.
The DispatcherTimer
XAML
In the XAML part of the program, we start off by declaring an instance of our
Audio & Video
converter as a resource for the window. We then have a TextBox, a couple of
TextBlocks and a CheckBox control and this is where the interesting things Playing audio
are happening: We bind the value of the TextBox to the TextBlock and the Playing video
CheckBox control and using the Converter property and our own converter How-to: Complete media
reference, we juggle the values back and forth between a string and a player
Boolean
value, depending on what's needed. Speech synthesis
Speech recognition
If you try to run this example, you will be able to change the value in two
places: By writing "yes" in the TextBox (or any other value, if you want false)
or by checking the CheckBox. No matter what you do, the change will be
reflected in the other control as well as in the TextBlock.
Summary
This was an example of a simple value converter, made a bit longer than
needed for illustrational purposes. In the next chapter we'll look into a more
advanced example, but before you go out and write your own converter, you
might want to check if WPF already includes one for the purpose. As of
writing,
there are more than 20 built-in converters that you may take
advantage of, but you need to know their name. I found the following list
which might come in
handy for you:
http://stackoverflow.com/questions/505397/built-in-wpf-ivalueconverters
Previous Next
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
The StringFormat property
Download this entire
tutorial as PDF right
now!
As we saw in the previous chapters, the way to manipulate the output of a About WPF
binding before is shown is typically through the use of a converter. The cool
What is WPF?
thing about the converters is that they allow you to convert any data type into
WPF vs. WinForms
a completely different data type. However, for more simple usage scenarios,
where you just want to change the way a certain value is shown and not
necessarily convert it into a different type, the StringFormat property might
very
well be enough. Getting started
Visual Studio Express
Using the StringFormat property of a binding, you lose some of the flexibility Hello, WPF!
you get when using a converter, but in return, it's much simpler to use and
doesn't involve the creation of a new class in a new file.
XAML
The StringFormat property does exactly what the name implies: It formats the
output string, simply by calling the String.Format method. Sometimes an What is XAML?
example says more than a thousand words, so before I hit that word count, Basic XAML
let's jump straight into an example: Events in XAML
<Window
x:Class="WpfTutorialSamples.DataBinding.StringFormatSample" A WPF application
Introduction
The Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta Working with App.xaml
Command-line parameters
Resources
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Handling exceptions
xmlns:system="clr-
namespace:System;assembly=mscorlib"
Title="StringFormatSample" Height="150" Basic controls
Width="250"
The TextBlock control
Name="wnd">
The TextBlock control - Inline
<StackPanel Margin="10">
formatting
<TextBlock Text="{Binding ElementName=wnd,
The Label control
Path=ActualWidth, StringFormat=Window width: {0:#,#.0}}"
The TextBox control
/>
The CheckBox control
<TextBlock Text="{Binding ElementName=wnd,
Data binding
The first couple of TextBlock's gets their value by binding to the parent
Introduction
Window and getting its width and height. Through the StringFormat property,
Hello, bound world!
the
values are formatted. For the width, we specify a custom formatting string
Using the DataContext
and for the height, we ask it to use the currency format, just for fun. The
The UpdateSourceTrigger
value is saved as a double type, so we can use all the same format specifiers
property
as if we had called double.ToString(). You can find a list of them here:
Responding to changes
http://msdn.microsoft.com/en-us/library/dwhawy9k.aspx
Value conversion with
IValueConverter
Also notice how I can include custom text in the StringFormat - this allows
The StringFormat property
you to pre/post-fix the bound value with text as you please. When referencing
Debugging data bindings
the actual value inside the format string, we surround it by a set of curly
braces, which includes two values: A reference to the value we want to
format
(value number 0, which is the first possible value) and the format
string, separated by a colon. Commands
Introduction
For the last two values, we simply bind to the current date (DateTime.Now) Using commands
and the output it first as a date, in a specific format, and then as the time Implementing custom
(hours and minutes), again using our own, pre-defined format. You can read commands
more about DateTime formatting here: http://msdn.microsoft.com/en-
us/library/az4se3k1.aspx
Common interface
Formatting without extra text controls
Please be aware that if you specify a format string that doesn't include any The Menu control
custom text, which all of the examples above does, then you need to add an The ContextMenu
extra set of curly braces, when defining it in XAML. The reason is that WPF The ToolBar control
may otherwise confuse the syntax with the one used for Markup Extensions. The StatusBar control
Here's an example: The Ribbon Control
<Window
x:Class="WpfTutorialSamples.DataBinding.StringFormatSample" Rich Text controls
Introduction
The
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta FlowDocumentScrollViewer
control
The
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
FlowDocumentPageViewer
xmlns:system="clr-
control
namespace:System;assembly=mscorlib"
The FlowDocumentReader
Title="StringFormatSample" Height="150"
control
Width="250"
Creating a FlowDocument
Name="wnd">
from Code-behind
<WrapPanel Margin="10">
Advanced FlowDocument
<TextBlock Text="Width: " />
content
<TextBlock Text="{Binding ElementName=wnd,
The RichTextBox control
Path=ActualWidth, StringFormat={}{0:#,#.0}}" />
</WrapPanel>
</Window>
Misc. controls
The Border control
The Slider control
Using a specific Culture The ProgressBar control
If you need to output a bound value in accordance with a specific culture, The WebBrowser control
that's no problem. The Binding will use the language specified for the parent The WindowsFormsHost
element, or you can specify it directly for the binding, using the control
ConverterCulture property. Here's an example:
List controls
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
The ItemsControl
xmlns:system="clr-
The ListBox control
namespace:System;assembly=mscorlib"
The ComboBox control
Title="StringFormatCultureSample" Height="120"
Width="300">
<StackPanel Margin="10">
The ListView control
<TextBlock Text="{Binding Source={x:Static
system:DateTime.Now}, ConverterCulture='de-DE', Introduction
StringFormat=German date: {0:D}}" /> A simple ListView
<TextBlock Text="{Binding Source={x:Static ListView, data binding and
system:DateTime.Now}, ConverterCulture='en-US', ItemTemplate
StringFormat=American date: {0:D}}" /> ListView with a GridView
<TextBlock Text="{Binding Source={x:Static How-to: Left aligned column
system:DateTime.Now}, ConverterCulture='ja-JP', names
StringFormat=Japanese date: {0:D}}" /> ListView grouping
</StackPanel> ListView sorting
</Window> How-to: ListView with
column sorting
ListView filtering
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
Debugging data bindings
Download this entire
tutorial as PDF right
now!
Since data bindings are evaluated at runtime, and no exceptions are thrown About WPF
when they fail, a bad binding can sometimes be very hard to track down.
What is WPF?
These
problems can occur in several different situations, but a common issue
WPF vs. WinForms
is when you try to bind to a property that doesn't exist, either because you
remembered its name wrong or because you simply misspelled it. Here's an
example:
Getting started
<Window Visual Studio Express
x:Class="WpfTutorialSamples.DataBinding.DataBindingDebugging Hello, WPF!
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta XAML
What is XAML?
Basic XAML
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Events in XAML
Title="DataBindingDebuggingSample" Height="100"
Width="200">
<Grid Margin="10" Name="pnlMain">
A WPF application
<TextBlock Text="{Binding
Introduction
NonExistingProperty, ElementName=pnlMain}" />
The Window
</Grid>
Working with App.xaml
</Window>
Command-line parameters
Resources
Handling exceptions
The Output window
The first place you will want to look is the Visual Studio Output window. It
should be at the bottom of your Visual Studio window, or you can activate it Basic controls
by using the [Ctrl+Alt+O] shortcut. There will be loads of output from the The TextBlock control
debugger, but somewhere you should find a line like this, when running the The TextBlock control - Inline
above
example: formatting
The Label control
System.Windows.Data Error: 40 : BindingExpression path error: The TextBox control
'NonExistingProperty' property not found on 'object' ''Grid' (Name='pnlMain')'. The CheckBox control
BindingExpression:Path=NonExistingProperty; DataItem='Grid'
This might seem a bit overwhelming, mainly because no linebreaks are used
in this long message, but the important part is this:
Panels
Introduction to WPF Panels
'NonExistingProperty' property not found on 'object' ''Grid' (Name='pnlMain')'. The Canvas
The WrapPanel
It tells you that you have tried to use a property called "NonExistingProperty" The StackPanel
on an object of the type Grid, with the name pnlMain. That's actually
pretty The DockPanel
concise and should help you correct the name of the property or bind to the The Grid
real object, if that's the problem. The Grid - Rows & Columns
The Grid - Units
Adjusting the trace level The Grid - Spanning
The above example was easy to fix, because it was clear to WPF what we The Grid - GridSplitter
were trying to do and why it didn't work. Consider this next example though: Using the Grid: A contact
form
<Window
x:Class="WpfTutorialSamples.DataBinding.DataBindingDebugging
Data binding
Introduction
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta Hello, bound world!
Using the DataContext
The UpdateSourceTrigger
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" property
Title="DataBindingDebuggingSample" Height="100" Responding to changes
Width="200"> Value conversion with
<Grid Margin="10"> IValueConverter
<TextBlock Text="{Binding Title}" /> The StringFormat property
</Grid> Debugging data bindings
</Window>
Commands
I'm trying to bind to the property "Title", but on which object? As stated in the Introduction
article on data contexts, WPF will use the DataContext property on the Using commands
TextBlock here, which may be inherited down the control hierarchy, but in Implementing custom
this example, I forgot to assign a data context. This basically means that I'm commands
trying to get a property on a NULL object. WPF will gather that this might be
a perfectly valid binding, but that the object just hasn't been initialized
yet,
and therefore it won't complain about it. If you run this example and look in Common interface
the Output window, you won't see any binding errors. controls
However, for the cases where this is not the behavior that you're expecting, The Menu control
there is a way to force WPF into telling you about all the binding problems it The ContextMenu
runs into. It can be done by setting the TraceLevel on the The ToolBar control
PresentationTraceSources object, which can be found in the The StatusBar control
System.Diagnostics namespace: The Ribbon Control
<Window
x:Class="WpfTutorialSamples.DataBinding.DataBindingDebugging Rich Text controls
Introduction
The
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta FlowDocumentScrollViewer
control
The
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" FlowDocumentPageViewer
xmlns:diag="clr- control
namespace:System.Diagnostics;assembly=WindowsBase" The FlowDocumentReader
Title="DataBindingDebuggingSample" Height="100" control
Width="200"> Creating a FlowDocument
<Grid Margin="10"> from Code-behind
<TextBlock Text="{Binding Title, Advanced FlowDocument
diag:PresentationTraceSources.TraceLevel=High}" /> content
</Grid> The RichTextBox control
</Window>
Misc. controls
Notice that I have added a reference to the System.Diagnostics namespace The Border control
in the top, and then used the property on the binding. WPF will now give you The Slider control
loads
of information about this specific binding in the Output window: The ProgressBar control
The WebBrowser control
System.Windows.Data Warning: 55 : Created The WindowsFormsHost
BindingExpression (hash=2902278) for Binding control
(hash=52760599)
System.Windows.Data Warning: 57 : Path: 'Title'
System.Windows.Data Warning: 59 : BindingExpression The TabControl
(hash=2902278): Default mode resolved to OneWay
Using the TabControl
System.Windows.Data Warning: 60 : BindingExpression
Tab positions
(hash=2902278): Default update trigger resolved to
Styling the TabItems
PropertyChanged
System.Windows.Data Warning: 61 : BindingExpression
(hash=2902278): Attach to
List controls
System.Windows.Controls.TextBlock.Text (hash=18876224)
System.Windows.Data Warning: 66 : BindingExpression The ItemsControl
(hash=2902278): Resolving source The ListBox control
System.Windows.Data Warning: 69 : BindingExpression The ComboBox control
(hash=2902278): Found data context element: TextBlock
(hash=18876224) (OK)
System.Windows.Data Warning: 70 : BindingExpression The ListView control
(hash=2902278): DataContext is null Introduction
System.Windows.Data Warning: 64 : BindingExpression A simple ListView
(hash=2902278): Resolve source deferred ListView, data binding and
System.Windows.Data Warning: 66 : BindingExpression ItemTemplate
(hash=2902278): Resolving source ListView with a GridView
System.Windows.Data Warning: 69 : BindingExpression How-to: Left aligned column
(hash=2902278): Found data context element: TextBlock names
(hash=18876224) (OK) ListView grouping
System.Windows.Data Warning: 70 : BindingExpression ListView sorting
(hash=2902278): DataContext is null How-to: ListView with
System.Windows.Data Warning: 66 : BindingExpression column sorting
(hash=2902278): Resolving source
ListView filtering
System.Windows.Data Warning: 69 : BindingExpression
(hash=2902278): Found data context element: TextBlock
(hash=18876224) (OK)
The TreeView control
System.Windows.Data Warning: 70 : BindingExpression
(hash=2902278): DataContext is null Introduction
System.Windows.Data Warning: 66 : BindingExpression A simple TreeView
(hash=2902278): Resolving source TreeView, data binding and
System.Windows.Data Warning: 69 : BindingExpression multiple templates
(hash=2902278): Found data context element: TextBlock Handling
(hash=18876224) (OK) Selection/Expansion state
System.Windows.Data Warning: 70 : BindingExpression Lazy loading TreeView items
(hash=2902278): DataContext is null
System.Windows.Data Warning: 66 : BindingExpression
(hash=2902278): Resolving source (last chance) The DataGrid control
System.Windows.Data Warning: 69 : BindingExpression Introduction
(hash=2902278): Found data context element: TextBlock Custom columns
(hash=18876224) (OK) Details row
System.Windows.Data Warning: 77 : BindingExpression
(hash=2902278): Activate with root item <null>
System.Windows.Data Warning: 105 : BindingExpression Styles
(hash=2902278): Item at level 0 is null - no accessor
Introduction
System.Windows.Data Warning: 79 : BindingExpression
Using styles
(hash=2902278): TransferValue - got raw value
Triggers
{DependencyProperty.UnsetValue}
Multi triggers
System.Windows.Data Warning: 87 : BindingExpression
Trigger animations
(hash=2902278): TransferValue - using fallback/default
value ''
System.Windows.Data Warning: 88 : BindingExpression
(hash=2902278): TransferValue - using final value '' Misc.
The DispatcherTimer
By reading through the list, you can actually see the entire process that WPF
goes through to try to find a proper value for your TextBlock control.
Several
times you will see it being unable to find a proper DataContext, and in the Audio & Video
end, it uses the default {DependencyProperty.UnsetValue} which
translates Playing audio
into an empty string. Playing video
How-to: Complete media
Using the real debugger player
Speech synthesis
The above trick can be great for diagnosing a bad binding, but for some
Speech recognition
cases, it's easier and more pleasant to work with the real debugger. Bindings
doesn't natively support this, since they are being handled deep inside of
WPF, but using a Converter, like shown in a previous article, you can actually
jump into this process and step through it. You don't really need a Converter
that does anything useful, you just need a way into the binding process, and
a dummy converter will get you there:
<Window
x:Class="WpfTutorialSamples.DataBinding.DataBindingDebugging
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:self="clr-
namespace:WpfTutorialSamples.DataBinding"
Title="DataBindingDebuggingSample" Name="wnd"
Height="100" Width="200">
<Window.Resources>
<self:DebugDummyConverter
x:Key="DebugDummyConverter" />
</Window.Resources>
<Grid Margin="10">
<TextBlock Text="{Binding Title,
ElementName=wnd, Converter={StaticResource
DebugDummyConverter}}" />
</Grid>
</Window>
using System;
using System.Windows;
using System.Windows.Data;
using System.Diagnostics;
namespace WpfTutorialSamples.DataBinding
{
public partial class DataBindingDebuggingSample :
Window
{
public DataBindingDebuggingSample()
{
InitializeComponent();
}
}
return value;
}
}
}
In the Code-behind file, we define a DebugDummyConverter. In the
Convert() and ConvertBack() methods, we call Debugger.Break(), which has
the same effect
as setting a breakpoint in Visual Studio, and then return the
value that was given to us untouched.
In the markup, we add a reference to our converter in the window resources
and then we use it in our binding. In a real world application, you should
define the converter in a file of its own and then add the reference to it in
App.xaml, so that you may use it all over the application without having to
create a new reference to it in each window, but for this example, the above
should do just fine.
If you run the example, you will see that the debugger breaks as soon as
WPF tries to fetch the value for the title of the window. You can now inspect
the
values given to the Convert() method, or even change them before
proceeding, using the standard debugging capabilities of Visual Studio.
If the debugger never breaks, it means that the converter is not used. This
usually indicates that you have an invalid binding expression, which can be
diagnosed and fixed using the methods described in the start of this article.
The dummy-converter trick is only for testing valid binding expressions.
Previous Next
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
Introduction to WPF Commands
Download this entire
tutorial as PDF right
now!
In a previous chapter of this tutorial, we talked about how to handle events, About WPF
e.g. when the user clicks on a button or a menu item. In a modern user
What is WPF?
interface, it's typical for a function to be reachable from several places
WPF vs. WinForms
though, invoked by different user actions.
For instance, if you have a typical interface with a main menu and a set of
toolbars, an action like New or Open might be available in the menu, on the Getting started
toolbar, in a context menu (e.g. when right clicking in the main application Visual Studio Express
area) and from a keyboard shortcut like Ctrl+N and Ctrl+O. Hello, WPF!
Each of these actions needs to perform what is typically the exact same
piece of code, so in a WinForms application, you would have to define an
XAML
event for
each of them and then call a common function. With the above
example, that would lead to at least three event handlers and some code to What is XAML?
handle the keyboard
shortcut. Not an ideal situation. Basic XAML
Events in XAML
Commands
With WPF, Microsoft is trying to remedy that with a concept called
A WPF application
commands. It allows you to define actions in one place and then refer to
them from all
your user interface controls like menu items, toolbar buttons Introduction
and so on. WPF will also listen for keyboard shortcuts and pass them along The Window
to the proper
command, if any, making it the ideal way to offer keyboard Working with App.xaml
shortcuts in an application. Command-line parameters
Resources
Commands also solve another hassle when dealing with multiple entrances Handling exceptions
to the same function. In a WinForms application, you would be responsible
for
writing code that could disable user interface elements when the action
was not available. For instance, if your application was able to use a Basic controls
clipboard
command like Cut, but only when text was selected, you would The TextBlock control
have to manually enable and disable the main menu item, the toolbar button The TextBlock control - Inline
and the context
menu item each time text selection changed. formatting
The Label control
With WPF commands, this is centralized. With one method you decide
The TextBox control
whether or not a given command can be executed, and then WPF toggles all
The CheckBox control
the subscribing
interface elements on or off automatically. This makes it so
Command bindings
Commands don't actually do anything by them self. At the root, they consist Panels
of the ICommand interface, which only defines an event and two methods:
Introduction to WPF Panels
Execute() and CanExecute(). The first one is for performing the actual action,
The Canvas
while the second one is for determining whether the action is currently
The WrapPanel
available. To perform the actual action of the command, you need a link
The StackPanel
between the command and your code and this is where the
The DockPanel
CommandBinding comes into
play.
The Grid
The Grid - Rows & Columns
A CommandBinding is usually defined on a Window or a UserControl, and
The Grid - Units
holds a references to the Command that it handles, as well as the actual
The Grid - Spanning
event
handlers for dealing with the Execute() and CanExecute() events of the
The Grid - GridSplitter
Command.
Using the Grid: A contact
Pre-defined commands form
You can of course implement your own commands, which we'll look into in
one of the next chapters, but to make it easier for you, the WPF team has Data binding
defined
over 100 commonly used commands that you can use. They have
Introduction
been divided into 5 categories, called ApplicationCommands,
Hello, bound world!
NavigationCommands, MediaCommands,
EditingCommands and
Using the DataContext
ComponentCommands. Especially ApplicationCommands contains
The UpdateSourceTrigger
commands for a lot of very frequently used actions like New, Open, Save and
property
Cut, Copy and Paste.
Responding to changes
Value conversion with
Summary IValueConverter
Commands help you to respond to a common action from several different The StringFormat property
sources, using a single event handler. It also makes it a lot easier to enable Debugging data bindings
and
disable user interface elements based on the current availability and
state. This was all theory, but in the next chapters we'll discuss how
commands are
used and how you define your own custom commands. Commands
Introduction
Previous Next Using commands
Implementing custom
commands
Introduction
The
FlowDocumentScrollViewer
control
The
FlowDocumentPageViewer
control
The FlowDocumentReader
control
Creating a FlowDocument
from Code-behind
Advanced FlowDocument
content
The RichTextBox control
Misc. controls
The Border control
The Slider control
The ProgressBar control
The WebBrowser control
The WindowsFormsHost
control
The TabControl
Using the TabControl
Tab positions
Styling the TabItems
List controls
The ItemsControl
The ListBox control
The ComboBox control
ListView filtering
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
Using WPF commands
Download this entire
tutorial as PDF right
now!
In the previous article, we discussed a lot of theory about what commands About WPF
are and how they work. In this chapter, we'll look into how you actually use
What is WPF?
commands, by assigning them to user interface elements and creating
WPF vs. WinForms
command bindings that links it all together.
We'll start off with a very simple example:
Getting started
<Window Visual Studio Express
x:Class="WpfTutorialSamples.Commands.UsingCommandsSample" Hello, WPF!
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
XAML
What is XAML?
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Basic XAML
Title="UsingCommandsSample" Height="100"
Events in XAML
Width="200">
<Window.CommandBindings>
<CommandBinding Command="ApplicationCommands.New"
A WPF application
Executed="NewCommand_Executed"
CanExecute="NewCommand_CanExecute" /> Introduction
</Window.CommandBindings> The Window
Working with App.xaml
<StackPanel HorizontalAlignment="Center" Command-line parameters
VerticalAlignment="Center"> Resources
<Button Handling exceptions
Command="ApplicationCommands.New">New</Button>
</StackPanel>
</Window> Basic controls
The TextBlock control
The TextBlock control - Inline
formatting
using System;
The Label control
using System.Collections.Generic;
The TextBox control
using System.Windows;
The CheckBox control
using System.Windows.Input;
We define a command binding on the Window, by adding it to its
CommandBindings collection. We specify that Command that we wish to use Commands
(the New command
from the ApplicationCommands), as well as two event
Introduction
handlers. The visual interface consists of a single button, which we attach the
Using commands
command to using the Command property.
Implementing custom
In Code-behind, we handle the two events. The CanExecute handler, which commands
WPF will call when the application is idle to see if the specific
command is
currently available, is very simple for this example, as we want this particular
command to be available all the time. This is done by setting
the Common interface
CanExecute property of the event arguments to true. controls
The Menu control
The Executed handler simply shows a message box when the command is
The ContextMenu
invoked. If you run the sample and press the button, you will see this
The ToolBar control
message. A thing to notice is that this command has a default keyboard
The StatusBar control
shortcut defined, which you get as an added bonus. Instead of clicking the
The Ribbon Control
button,
you can try to press Ctrl+N on your keyboard - the result is the same.
Using the CanExecute method
Rich Text controls
In the first example, we implemented a CanExecute event that simply Introduction
returned true, so that the button would be available all the time. However, this The
is of
course not true for all buttons - in many cases, you want the button to be FlowDocumentScrollViewer
enabled or disabled depending on some sort of state in your application. control
The
A very common example of this is the toggling of buttons for using the
FlowDocumentPageViewer
Windows Clipboard, where you want the Cut and Copy buttons to be enabled
control
only when
text is selected, and the Paste button to only be enabled when text
The FlowDocumentReader
is present in the clipboard. This is exactly what we'll accomplish in this
control
example:
Creating a FlowDocument
from Code-behind
<Window Advanced FlowDocument
x:Class="WpfTutorialSamples.Commands.CommandCanExecuteSample content
The RichTextBox control
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
Misc. controls
The Border control
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
The Slider control
Title="CommandCanExecuteSample" Height="200"
The ProgressBar control
Width="250">
The WebBrowser control
<Window.CommandBindings>
The WindowsFormsHost
<CommandBinding Command="ApplicationCommands.Cut"
control
CanExecute="CutCommand_CanExecute"
Executed="CutCommand_Executed" />
<CommandBinding
Command="ApplicationCommands.Paste" The TabControl
CanExecute="PasteCommand_CanExecute" Using the TabControl
Executed="PasteCommand_Executed" /> Tab positions
</Window.CommandBindings> Styling the TabItems
<DockPanel>
<WrapPanel DockPanel.Dock="Top" Margin="3">
<Button Command="ApplicationCommands.Cut" List controls
Width="60">_Cut</Button>
The ItemsControl
<Button Command="ApplicationCommands.Paste"
The ListBox control
Width="60" Margin="3,0">_Paste</Button>
The ComboBox control
</WrapPanel>
<TextBox AcceptsReturn="True" Name="txtEditor" />
</DockPanel>
</Window>
The ListView control
Introduction
A simple ListView
ListView, data binding and
using System; ItemTemplate
using System.Collections.Generic; ListView with a GridView
using System.Windows; How-to: Left aligned column
using System.Windows.Input; names
ListView grouping
namespace WpfTutorialSamples.Commands ListView sorting
{ How-to: ListView with
public partial class CommandCanExecuteSample : column sorting
So, we have this very simple interface with a couple of buttons and a
TextBox control. The first button will cut to the clipboard and the second one
will
paste from it.
In Code-behind, we have two events for each button: One that performs the
actual action, which name ends with _Executed, and then the CanExecute
events. In
each of them, you will see that I apply some logic to decide
whether or not the action can be executed and then assign it to the return
value CanExecute on the EventArgs.
The cool thing about this is that you don't have to call these methods to have
your buttons updated - WPF does it automatically when the application has
an
idle moment, making sure that you interface remains updated all the time.
Default command behavior and
CommandTarget
As we saw in the previous example, handling a set of commands can lead to
quite a bit of code, with a lot of being method declarations and very standard
logic. That's probably why the WPF team decided to handle some it for you.
In fact, we could have avoided all of the Code-behind in the previous
example,
because a WPF TextBox can automatically handle common
commands like Cut, Copy, Paste, Undo and Redo.
WPF does this by handling the Executed and CanExecute events for you,
when a text input control like the TextBox has focus. You are free to override
these
events, which is basically what we did in the previous example, but if
you just want the basic behavior, you can let WPF connect the commands
and the
TextBox control and do the work for you. Just see how much simpler
this example is:
<Window
x:Class="WpfTutorialSamples.Commands.CommandsWithCommandTarg
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="CommandsWithCommandTargetSample"
Height="200" Width="250">
<DockPanel>
<WrapPanel DockPanel.Dock="Top" Margin="3">
<Button Command="ApplicationCommands.Cut"
CommandTarget="{Binding ElementName=txtEditor}"
Width="60">_Cut</Button>
<Button Command="ApplicationCommands.Paste"
CommandTarget="{Binding ElementName=txtEditor}" Width="60"
Margin="3,0">_Paste</Button>
</WrapPanel>
<TextBox AcceptsReturn="True" Name="txtEditor" />
</DockPanel>
</Window>
No Code-behind code needed for this example - WPF deals with all of it for
us, but only because we want to use these specific commands for this
specific
control. The TextBox does the work for us.
Notice how I use the CommandTarget properties on the buttons, to bind the
commands to our TextBox control. This is required in this
particular example,
because the WrapPanel doesn't handle focus the same way e.g. a Toolbar or
a Menu would, but it also makes pretty good sense to give the
commands a
target.
Summary
Dealing with commands is pretty straight forward, but does involve a bit extra
markup and code. The reward is especially obvious when you need to invoke
the same action from multiple places though, or when you use built-in
commands that WPF can handle completely for you, as we saw in the last
example.
Previous Next
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
Implementing a custom WPF
Command Download this entire
tutorial as PDF right
now!
About WPF
In the previous chapter, we looked at various ways of using commands
What is WPF?
already defined in WPF, but of course you can implement your own
WPF vs. WinForms
commands as well.
It's pretty simply, and once you've done it, you can use
your own commands just like the ones defined in WPF.
The easiest way to start implementing your own commands is to have a Getting started
static class that will contain them. Each command is then added to this class Visual Studio Express
as static fields, allowing you to use them in your application. Since WPF, for Hello, WPF!
some strange reason, doesn't implement an Exit/Quit command, I decided to
implement one for our custom commands example. It looks like this:
XAML
<Window
What is XAML?
x:Class="WpfTutorialSamples.Commands.CustomCommandSample"
Basic XAML
Events in XAML
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
A WPF application
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:self="clr- Introduction
namespace:WpfTutorialSamples.Commands" The Window
Title="CustomCommandSample" Height="150" Working with App.xaml
Width="200"> Command-line parameters
<Window.CommandBindings> Resources
<CommandBinding Command="self:CustomCommands.Exit" Handling exceptions
CanExecute="ExitCommand_CanExecute"
Executed="ExitCommand_Executed" />
</Window.CommandBindings> Basic controls
<Grid> The TextBlock control
<Grid.RowDefinitions> The TextBlock control - Inline
<RowDefinition Height="Auto" /> formatting
<RowDefinition Height="*" /> The Label control
</Grid.RowDefinitions> The TextBox control
<Menu> The CheckBox control
<MenuItem Header="File">
{ Introduction
new The
KeyGesture(Key.F4, ModifierKeys.Alt) FlowDocumentScrollViewer
} control
); The
FlowDocumentPageViewer
//Define more commands here, just like the control
one above The FlowDocumentReader
} control
} Creating a FlowDocument
from Code-behind
Advanced FlowDocument
content
The RichTextBox control
Misc. controls
The Border control
The Slider control
The ProgressBar control
In the markup, I've defined a very simple interface with a menu and a button, The WebBrowser control
both of them using our new, custom Exit command. This command is defined The WindowsFormsHost
in
Code-behind, in our own CustomCommands class, and then referenced control
in the CommandBindings collection of the window, where we assign the
events that it should use to execute/check if it's allowed to execute.
The TabControl
All of this is just like the examples in the previous chapter, except for the fact
that we're referencing the command from our own code (using the "self" Using the TabControl
namespace defined in the top) instead of a built-in command. Tab positions
Styling the TabItems
In Code-behind, we respond to the two events for our command: One event
just allows the command to execute all the time, since that's usually true for
an
exit/quit command, and the other one calls the Shutdown method that will List controls
terminate our application. All very simple.
The ItemsControl
The ListBox control
As already explained, we implement our Exit command as a field on a static
The ComboBox control
CustomCommands class. There are several ways of defining and assigning
properties on the commands, but I've chosen the more compact approach (it
would be even more compact if placed on the same line, but I've added line
breaks
here for readability) where I assign all of it through the constructor. The ListView control
The parameters are the text/label of the command, the name of the Introduction
command, the
owner type and then an InputGestureCollection, allowing me A simple ListView
to define a default shortcut for the command (Alt+F4). ListView, data binding and
ItemTemplate
Summary ListView with a GridView
How-to: Left aligned column
Implementing custom WPF commands is almost as easy as consuming the
names
built-in commands, and it allows you to use commands for every purpose in
ListView grouping
your
application. This makes it very easy to re-use actions in several places,
ListView sorting
as shown in the example of this chapter.
How-to: ListView with
column sorting
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
The WPF Menu control
Download this entire
tutorial as PDF right
now!
One of the most common parts of a Windows application is the menu, About WPF
sometimes referred to as the main menu because only one usually exists in
What is WPF?
the
application. The menu is practical because it offers a lot of options, using
WPF vs. WinForms
only very little space, and even though Microsoft is pushing the Ribbon as a
replacement for the good, old menu and toolbars, they definitely still have
their place in every good developer's toolbox.
Getting started
WPF comes with a fine control for creating menus called... Menu. Adding Visual Studio Express
items to it is very simple - you simply add MenuItem elements to it, and each Hello, WPF!
MenuItem can have a range of sub-items, allowing you to create hierarchical
menus as you know them from a lot of Windows applications. Let's jump
straight
to an example where we use the Menu:
XAML
What is XAML?
<Window
Basic XAML
x:Class="WpfTutorialSamples.Common_interface_controls.MenuSa
Events in XAML
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
A WPF application
Introduction
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" The Window
Title="MenuSample" Height="200" Width="200"> Working with App.xaml
<DockPanel> Command-line parameters
<Menu DockPanel.Dock="Top"> Resources
<MenuItem Header="_File"> Handling exceptions
<MenuItem Header="_New" />
<MenuItem Header="_Open" />
<MenuItem Header="_Save" /> Basic controls
<Separator /> The TextBlock control
<MenuItem Header="_Exit" /> The TextBlock control - Inline
</MenuItem> formatting
</Menu> The Label control
<TextBox AcceptsReturn="True" /> The TextBox control
</DockPanel> The CheckBox control
</Window>
Panels
Introduction to WPF Panels
The Canvas
The WrapPanel
The StackPanel
The DockPanel
The Grid
The Grid - Rows & Columns
The Grid - Units
The Grid - Spanning
As in most Windows applications, my menu is placed in the top of the The Grid - GridSplitter
window, but in keeping with the enormous flexibility of WPF, you can actually Using the Grid: A contact
place a
Menu control wherever you like, and in any width or height that you form
may desire.
I have defined a single top-level item, with 4 child items and a separator. I
Data binding
use the Header property to define the label of the item, and
you should
notice the underscore before the first character of each label. It tells WPF to Introduction
use that character as the accelerator key, which means that the
user can Hello, bound world!
press the Alt key followed by the given character, to activate the menu item. Using the DataContext
This works all the way from the top-level item and down the
hierarchy, The UpdateSourceTrigger
meaning that in this example I could press Alt, then F and then N, to activate property
the New item. Responding to changes
Value conversion with
Icons and checkboxes IValueConverter
The StringFormat property
Two common features of a menu item is the icon, used to more easily identify Debugging data bindings
the menu item and what it does, and the ability to have checkable menu
items,
which can toggle a specific feature on and off. The WPF MenuItem
supports both, and it's very easy to use:
Commands
Introduction
<Window
Using commands
x:Class="WpfTutorialSamples.Common_interface_controls.MenuIc
Implementing custom
commands
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
Common interface
controls
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MenuIconCheckableSample" Height="150" The Menu control
Width="300"> The ContextMenu
<DockPanel> The ToolBar control
<Menu DockPanel.Dock="Top"> The StatusBar control
<MenuItem Header="_File"> The Ribbon Control
<MenuItem Header="_Exit" />
</MenuItem>
<MenuItem Header="_Tools"> Rich Text controls
Misc. controls
The Border control
The Slider control
The ProgressBar control
The WebBrowser control
The WindowsFormsHost
control
For this example I've created a secondary top-level item, where I've added
two items: One with an icon defined, using the Icon property
with a standard
Image control inside of it, and one where we use the IsCheckable property The TabControl
to allow the user to check and uncheck the item.
I even used the IsChecked Using the TabControl
property to have it checked by default. From Code-behind, this is the same Tab positions
property that you can read to know
whether a given menu item is checked or Styling the TabItems
not.
Handling clicks List controls
When the user clicks on a menu item, you will usually want something to The ItemsControl
happen. The easiest way is to simply add a click event handler to the The ListBox control
MenuItem,
like this: The ComboBox control
ListView filtering
Keyboard shortcuts and Commands
You can easily handle the Click event of a menu item like we did above, but The TreeView control
the more common approach is to use WPF commands. There's a lot of Introduction
theory on
using and creating commands, so they have their own category of A simple TreeView
articles here on the site, but for now, I can tell you that they have a couple of TreeView, data binding and
advantages when used in WPF, especially in combination with a Menu or a multiple templates
Toolbar. Handling
Selection/Expansion state
First of all, they ensure that you can have the same action on a toolbar, a
Lazy loading TreeView items
menu and even a context menu, without having to implement the same code
in
multiple places. They also make the handling of keyboard shortcuts a
whole lot easier, because unlike with WinForms, WPF is not listening for
keyboard
shortcuts automatically if you assign them to e.g. a menu item - you
The DataGrid control
will have to do that manually. Introduction
Custom columns
However, when using commands, WPF is all ears and will respond to Details row
keyboard shortcuts automatically. The text (Header) of the menu item is also
set
automatically (although you can overwrite it if needed), and so is the
InputGestureText, which shows the user which keyboard shortcut can be Styles
used to invoke
the specific menu item. Let's jump straight to an example of
Introduction
combining the Menu with WPF commands:
Using styles
Triggers
<Window Multi triggers
x:Class="WpfTutorialSamples.Common_interface_controls.MenuWi
Trigger animations
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
Misc.
The DispatcherTimer
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MenuWithCommandsSample" Height="200"
Width="300"> Audio & Video
<Window.CommandBindings> Playing audio
<CommandBinding Command="New" Playing video
CanExecute="NewCommand_CanExecute" How-to: Complete media
Executed="NewCommand_Executed" /> player
</Window.CommandBindings> Speech synthesis
<DockPanel> Speech recognition
<Menu DockPanel.Dock="Top">
<MenuItem Header="_File">
<MenuItem Command="New" />
<Separator />
<MenuItem Header="_Exit" />
</MenuItem>
<MenuItem Header="_Edit">
<MenuItem Command="Cut" />
<MenuItem Command="Copy" />
<MenuItem Command="Paste" />
</MenuItem>
</Menu>
using System;
using System.Windows;
using System.Windows.Input;
namespace WpfTutorialSamples.Common_interface_controls
{
public partial class MenuWithCommandsSample :
Window
{
public MenuWithCommandsSample()
{
InitializeComponent();
}
It might not be completely obvious, but by using commands, we just got a
whole bunch of things for free: Keyboard shortcuts, text and
InputGestureText on the items and WPF automatically enables/disables the
And because WPF knows how to handle certain commands in combination
with certain controls, in this case the Cut/Copy/Paste commands in
combination with a
text input control, we don't even have to handle their
Execute events - they work right out of the box! We do have to handle it for
theNew command though, since WPF has no way of guessing what we want
it to do when the user activates it. This is done with the CommandBindings
of the Window, all explained in detail in the chapter on commands.
Summary
Working with the WPF Menu control is both easy and fast, making it simple to
create even complex menu hierarchies, and when combining it with WPF
commands,
you get so much functionality for free.
Previous Next
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
The WPF ContextMenu
Download this entire
tutorial as PDF right
now!
A context menu, often referred to as a popup or pop-up menu, is a menu About WPF
which is shown upon certain user actions, usually a right-click with the mouse
What is WPF?
on a
specific control or window. Contextual menus are often used to offer
WPF vs. WinForms
functionality that's relevant within a single control.
WPF comes with a ContextMenu control and because it's almost always tied
to a specific control, that's also usually how you add it to the interface. This
is Getting started
done through the ContextProperty, which all controls exposes (it comes from Visual Studio Express
the FrameworkElement which most WPF controls inherits from). Consider the Hello, WPF!
next example to see how it's done:
<Window XAML
x:Class="WpfTutorialSamples.Common_interface_controls.Contex
What is XAML?
Basic XAML
Events in XAML
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
A WPF application
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ContextMenuSample" Height="250" Introduction
Width="250"> The Window
<Grid> Working with App.xaml
<Button Content="Right-click me!" Command-line parameters
VerticalAlignment="Center" HorizontalAlignment="Center"> Resources
<Button.ContextMenu> Handling exceptions
<ContextMenu>
<MenuItem Header="Menu item 1" />
<MenuItem Header="Menu item 2" /> Basic controls
<Separator /> The TextBlock control
<MenuItem Header="Menu item 3" /> The TextBlock control - Inline
</ContextMenu> formatting
</Button.ContextMenu> The Label control
</Button> The TextBox control
</Grid> The CheckBox control
</Window>
Panels
Introduction to WPF Panels
The Canvas
The WrapPanel
The StackPanel
The DockPanel
The Grid
The Grid - Rows & Columns
The Grid - Units
The Grid - Spanning
The Grid - GridSplitter
Using the Grid: A contact
form
If you've already read the chapter on the regular menu, you will soon realize
that the ContextMenu works exactly the same way, and no wonder, since
they
both inherit the MenuBase class. Just like we saw in the examples on
using the regular Menu, you can of course add Click events to these items to Data binding
handle
when the user clicks on them, but a more WPF-suitable way is to use Introduction
Commands. Hello, bound world!
Using the DataContext
ContextMenu with Commands and icons The UpdateSourceTrigger
property
In this next example, I'm going to show you two key concepts when using the
Responding to changes
ContextMenu: The usage of WPF Commands, which will provide us with lots
Value conversion with
of
functionality including a Click event handler, a text and a shortcut text,
IValueConverter
simply by assigning something to the Command property. I will also show
The StringFormat property
you to
use icons on your ContextMenu items. Have a look:
Debugging data bindings
<Window
x:Class="WpfTutorialSamples.Common_interface_controls.Contex
Commands
Introduction
Using commands
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
Implementing custom
commands
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ContextMenuWithCommandsSample" Height="200"
Width="250"> Common interface
<StackPanel Margin="10"> controls
<TextBox Text="Right-click here for context The Menu control
menu!"> The ContextMenu
<TextBox.ContextMenu> The ToolBar control
<ContextMenu> The StatusBar control
<MenuItem Command="Cut"> The Ribbon Control
<MenuItem.Icon>
<Image
Source="/WpfTutorialSamples;component/Images/cut.png" /> Rich Text controls
</MenuItem.Icon>
Introduction
</MenuItem>
The
<MenuItem Command="Copy">
FlowDocumentScrollViewer
<MenuItem.Icon>
control
<Image
The
Source="/WpfTutorialSamples;component/Images/copy.png" />
FlowDocumentPageViewer
</MenuItem.Icon>
control
</MenuItem>
The FlowDocumentReader
<MenuItem Command="Paste">
control
<MenuItem.Icon>
Creating a FlowDocument
<Image
from Code-behind
Source="/WpfTutorialSamples;component/Images/paste.png" />
Advanced FlowDocument
</MenuItem.Icon>
content
</MenuItem>
The RichTextBox control
</ContextMenu>
</TextBox.ContextMenu>
</TextBox>
Misc. controls
</StackPanel>
</Window> The Border control
The Slider control
The ProgressBar control
The WebBrowser control
The WindowsFormsHost
control
The TabControl
Using the TabControl
Tab positions
Styling the TabItems
Try running the example and see for yourself how much functionality we get List controls
for free by assigning commands to the items. Also notice how fairly simple it The ItemsControl
is
to use icons on the menu items of the ContextMenu. The ListBox control
The ComboBox control
Invoke ContextMenu from Code-behind
So far, the ContextMenu has been invoked when right-clicking on the control
to which it belongs. WPF does this for us automatically, when we assign it to The ListView control
the ContextMenu property. However, in some situations, you might very well Introduction
want to invoke it manually from code. This is pretty easy as
well, so let's re- A simple ListView
use the first example to demonstrate it with: ListView, data binding and
ItemTemplate
<Window ListView with a GridView
x:Class="WpfTutorialSamples.Common_interface_controls.Contex How-to: Left aligned column
names
ListView grouping
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta ListView sorting
How-to: ListView with
column sorting
The first thing you should notice is that I've moved the ContextMenu away
from the button. Instead, I've added it as a resource of the Window, to make
it
available from all everywhere within the Window. This also makes it a lot
easier to find when we need to show it.
The Button now has a Click event handler, which I handle in Code-behind.
From there, I simply find the ContextMenu instance within the window
resources and
then I do two things: I set it's PlacementTarget property, which
tells WPF which element it should calculate the position based on, and then I
set the
IsOpen to true, to open the menu. That's all you need!
Previous Next
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
The WPF ToolBar control
Download this entire
tutorial as PDF right
now!
The toolbar is a row of commands, usually sitting right below the main menu About WPF
of a standard Windows application. This could in fact be a simple panel with
What is WPF?
buttons on it, but by using the WPF ToolBar control, you get some extra
WPF vs. WinForms
goodies like automatic overflow handling and the possibility for the end-user
to
re-position your toolbars.
A WPF ToolBar is usually placed inside of a ToolBarTray control. The Getting started
ToolBarTray will handle stuff like placement and sizing, and you can have Visual Studio Express
multiple
ToolBar controls inside of the ToolBarTray element. Let's try a pretty Hello, WPF!
basic example, to see what it all looks like:
<Window XAML
x:Class="WpfTutorialSamples.Common_interface_controls.Toolba
What is XAML?
Basic XAML
Events in XAML
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
A WPF application
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ToolbarSample" Height="200" Width="300"> Introduction
<Window.CommandBindings> The Window
<CommandBinding Command="New" Working with App.xaml
CanExecute="CommonCommandBinding_CanExecute" /> Command-line parameters
<CommandBinding Command="Open" Resources
CanExecute="CommonCommandBinding_CanExecute" /> Handling exceptions
<CommandBinding Command="Save"
CanExecute="CommonCommandBinding_CanExecute" />
</Window.CommandBindings> Basic controls
<DockPanel> The TextBlock control
<ToolBarTray DockPanel.Dock="Top"> The TextBlock control - Inline
<ToolBar> formatting
<Button Command="New" Content="New" /> The Label control
<Button Command="Open" Content="Open" /> The TextBox control
<Button Command="Save" Content="Save" /> The CheckBox control
</ToolBar>
Common interface
controls
The Menu control
The ContextMenu
The ToolBar control
Notice how I use commands for all the buttons. We discussed this in the The StatusBar control
previous chapter and using commands definitely gives us some advantages. The Ribbon Control
Take a
look at the Menu chapter, or the articles on commands, for more
information.
Rich Text controls
In this example, I add a ToolBarTray to the top of the screen, and inside of it, Introduction
two ToolBar controls. Each contains some buttons and we use commands to The
give them their behavior. In Code-behind, I make sure to handle the FlowDocumentScrollViewer
CanExecute event of the first three buttons, since that's not done control
automatically by
WPF, contrary to the Cut, Copy and Paste commands, The
which WPF is capable of fully handling for us. FlowDocumentPageViewer
control
Try running the example and place the cursor over the left part of one of the
The FlowDocumentReader
toolbars (the dotted area). If you click and hold your left mouse button, you
control
can now re-position the toolbar, e.g. below the other or even make them
Creating a FlowDocument
switch place.
from Code-behind
Images Advanced FlowDocument
content
While text on the toolbar buttons is perfectly okay, the normal approach is to The RichTextBox control
have icons or at least a combination of an icon and a piece of text. Because
WPF uses regular Button controls, adding icons to the toolbar items is very
easy. Just have a look at this next example, where we do both: Misc. controls
The Border control
<Window The Slider control
x:Class="WpfTutorialSamples.Common_interface_controls.Toolba The ProgressBar control
The WebBrowser control
The WindowsFormsHost
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta control
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
The TabControl
Title="ToolbarIconSample" Height="200"
Using the TabControl
Width="300">
Tab positions
<DockPanel>
Styling the TabItems
<ToolBarTray DockPanel.Dock="Top">
<ToolBar>
<Button Command="Cut" ToolTip="Cut
selection to Windows Clipboard."> List controls
<Image The ItemsControl
Source="/WpfTutorialSamples;component/Images/cut.png" /> The ListBox control
</Button> The ComboBox control
<Button Command="Copy" ToolTip="Copy
selection to Windows Clipboard.">
<Image The ListView control
Source="/WpfTutorialSamples;component/Images/copy.png" />
Introduction
</Button>
A simple ListView
<Button Command="Paste" ToolTip="Paste
ListView, data binding and
from Windows Clipboard.">
ItemTemplate
<StackPanel Orientation="Horizontal">
ListView with a GridView
<Image
How-to: Left aligned column
Source="/WpfTutorialSamples;component/Images/paste.png" />
names
<TextBlock
ListView grouping
Margin="3,0,0,0">Paste</TextBlock>
ListView sorting
</StackPanel>
How-to: ListView with
</Button>
column sorting
</ToolBar>
ListView filtering
</ToolBarTray>
<TextBox AcceptsReturn="True" />
</DockPanel>
The TreeView control
</Window>
Introduction
A simple TreeView
TreeView, data binding and
multiple templates
Handling
Selection/Expansion state
Lazy loading TreeView items
WPF even allows you to decide which items are suitable for overflow hiding
and which should always be visible. Usually, when designing a toolbar, some
items are less important than the others and some of them you might even
want to have in the overflow menu all the time, no matter if there's space
enough
or not.
This is where the attached property ToolBar.OverflowMode comes into
play. The default value is IfNeeded, which simply means that a toolbar
item is
put in the overflow menu if there's not enough room for it. You may use
Always or Never instead, which does
exactly what the names imply: Puts
the item in the overflow menu all the time or prevents the item from ever
being moved to the overflow menu. Here's an
example on how to assign this
property:
<ToolBar>
<Button Command="Cut" Content="Cut"
ToolBar.OverflowMode="Always" />
<Button Command="Copy" Content="Copy"
ToolBar.OverflowMode="AsNeeded" />
<Button Command="Paste" Content="Paste"
ToolBar.OverflowMode="Never" />
</ToolBar>
Position
While the most common position for the toolbar is indeed in the top of the
screen, toolbars can also be found in the bottom of the application window or
even on the sides. The WPF ToolBar of course supports all of this, and while
the bottom placed toolbar is merely a matter of docking to the bottom of the
panel instead of the top, a vertical toolbar requires the use of the Orientation
property of the ToolBar tray. Allow me to demonstrate
with an example:
<Window
x:Class="WpfTutorialSamples.Common_interface_controls.Toolba
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ToolbarPositionSample" Height="200"
Width="300">
<DockPanel>
<ToolBarTray DockPanel.Dock="Top">
<ToolBar>
<Button Command="Cut"
ToolTip="Cut selection to Windows Clipboard.">
<Image
Source="/WpfTutorialSamples;component/Images/cut.png" />
</Button>
<Button Command="Copy"
ToolTip="Copy selection to Windows Clipboard.">
<Image
Source="/WpfTutorialSamples;component/Images/copy.png" />
</Button>
<Button Command="Paste"
ToolTip="Paste from Windows Clipboard.">
<StackPanel
Orientation="Horizontal">
<Image
Source="/WpfTutorialSamples;component/Images/paste.png" />
<TextBlock
Margin="3,0,0,0">Paste</TextBlock>
</StackPanel>
</Button>
</ToolBar>
</ToolBarTray>
<ToolBarTray DockPanel.Dock="Right"
Orientation="Vertical">
<ToolBar>
<Button Command="Cut"
ToolTip="Cut selection to Windows Clipboard.">
<Image
Source="/WpfTutorialSamples;component/Images/cut.png" />
</Button>
<Button Command="Copy"
ToolTip="Copy selection to Windows Clipboard.">
<Image
Source="/WpfTutorialSamples;component/Images/copy.png" />
</Button>
<Button Command="Paste"
ToolTip="Paste from Windows Clipboard.">
<Image
Source="/WpfTutorialSamples;component/Images/paste.png" />
</Button>
</ToolBar>
</ToolBarTray>
<TextBox AcceptsReturn="True" />
</DockPanel>
</Window>
The trick here lies in the combination of the DockPanel.Dock property, that
puts the ToolBarTray to the right of the application, and the Orientation
property, that changes the orientation from horizontal to vertical. This makes
it possible to place toolbars in pretty much
any location that you might think
of.
Custom controls on the ToolBar
As you have seen on all of the previous examples, we use regular WPF
Button controls on the toolbars. This also means that you can place pretty
much any
other WPF control on the toolbars, with no extra effort. Of course,
some controls works better on a toolbar than others, but controls like the
ComboBox and
TextBox are commonly used on the toolbars in e.g. older
versions of Microsoft Office, and you can do the same on your own WPF
toolbars.
Another thing introduced in this example is the Separator element, which
simply creates a separator between two sets of toolbar items. As you can see
from
the example, it's very easy to use!
<Window
x:Class="WpfTutorialSamples.Common_interface_controls.Toolba
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ToolbarCustomControlsSample" Height="200"
Width="300">
<DockPanel>
<ToolBarTray DockPanel.Dock="Top">
<ToolBar>
<Button Command="Cut"
ToolTip="Cut selection to Windows Clipboard.">
<Image
Source="/WpfTutorialSamples;component/Images/cut.png" />
</Button>
<Button Command="Copy"
ToolTip="Copy selection to Windows Clipboard.">
<Image
Source="/WpfTutorialSamples;component/Images/copy.png" />
</Button>
<Button Command="Paste"
ToolTip="Paste from Windows Clipboard.">
<StackPanel
Orientation="Horizontal">
<Image
Source="/WpfTutorialSamples;component/Images/paste.png" />
<TextBlock
Margin="3,0,0,0">Paste</TextBlock>
</StackPanel>
</Button>
<Separator />
<Label>Font size:</Label>
<ComboBox>
<ComboBoxItem>10</ComboBoxItem>
<ComboBoxItem
IsSelected="True">12</ComboBoxItem>
<ComboBoxItem>14</ComboBoxItem>
<ComboBoxItem>16</ComboBoxItem>
</ComboBox>
</ToolBar>
</ToolBarTray>
<TextBox AcceptsReturn="True" />
</DockPanel>
</Window>
Summary
Creating interfaces with toolbars is very easy in WPF, with the flexible
ToolBar control. You can do things that previously required 3rd party toolbar
controls and you can even do it without much extra effort.
Previous Next
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
The WPF StatusBar control
Download this entire
tutorial as PDF right
now!
With the top of the application window usually occupied by the main menu About WPF
and/or toolbars, described in previous chapters, the bottom part of the
What is WPF?
window is
usually the home of the status bar. The status bar is used to show
WPF vs. WinForms
various information about the current state of the application, like cursor
position,
word count, progress of tasks and so on. Fortunately for us, WPF
comes with a nice StatusBar control, making it very easy to add status bar
functionality
to your applications. Getting started
Visual Studio Express
Let's start off with a very basic example: Hello, WPF!
<Window
x:Class="WpfTutorialSamples.Common_interface_controls.Status XAML
What is XAML?
Basic XAML
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
Events in XAML
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
A WPF application
Title="StatusBarSample" Height="150" Width="300">
<DockPanel> Introduction
<StatusBar DockPanel.Dock="Bottom"> The Window
<StatusBarItem> Working with App.xaml
<TextBlock Command-line parameters
Name="lblCursorPosition" /> Resources
</StatusBarItem> Handling exceptions
</StatusBar>
<TextBox AcceptsReturn="True"
Name="txtEditor" Basic controls
SelectionChanged="txtEditor_SelectionChanged" /> The TextBlock control
</DockPanel> The TextBlock control - Inline
</Window> formatting
The Label control
The TextBox control
The CheckBox control
using System;
namespace WpfTutorialSamples.Common_interface_controls
{
public partial class StatusBarSample : Window Panels
{ Introduction to WPF Panels
public StatusBarSample() The Canvas
{ The WrapPanel
InitializeComponent(); The StackPanel
} The DockPanel
The Grid
private void The Grid - Rows & Columns
txtEditor_SelectionChanged(object sender, RoutedEventArgs The Grid - Units
e) The Grid - Spanning
{ The Grid - GridSplitter
Using the Grid: A contact
int row = form
txtEditor.GetLineIndexFromCharacterIndex(txtEditor.CaretInde
Commands
Introduction
Using commands
Implementing custom
It's all very simple - a TextBlock control that shows the current cursor commands
position, just like in pretty much any other application that allows you to edit
text. In this very basic form, the StatusBar could just as easily have been a
panel with a set of controls on it, but the real advantage of the StatusBar Common interface
comes when we need to divide it into several areas of information. controls
The Menu control
Advanced StatusBar example The ContextMenu
Let's try a more advanced example of using the StatusBar. The first thing we The ToolBar control
want to do is to make the StatusBar use another panel for the layout. By The StatusBar control
default, it uses the DockPanel, but when we want a more complex layout, The Ribbon Control
with columns that adjusts its width in a certain way and aligned
content, the
Grid is a much better choice.
Rich Text controls
We'll divide the Grid into three areas, with the left and right one having a
Introduction
fixed width and the middle column automatically taking up the
remaining
The
space. We'll also add columns in between for Separator controls. Here's how
FlowDocumentScrollViewer
it looks now:
control
The
<Window FlowDocumentPageViewer
x:Class="WpfTutorialSamples.Common_interface_controls.Status control
The FlowDocumentReader
control
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta Creating a FlowDocument
from Code-behind
Advanced FlowDocument
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" content
Title="StatusBarAdvancedSample" Height="150" The RichTextBox control
Width="400">
<DockPanel>
<StatusBar DockPanel.Dock="Bottom">
Misc. controls
<StatusBar.ItemsPanel>
<ItemsPanelTemplate> The Border control
<Grid> The Slider control
<Grid.ColumnDefinitions> The ProgressBar control
<ColumnDefinition Width="100" The WebBrowser control
/> The WindowsFormsHost
<ColumnDefinition Width="Auto" control
/>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" The TabControl
/> Using the TabControl
<ColumnDefinition Width="100" Tab positions
/> Styling the TabItems
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate> List controls
</StatusBar.ItemsPanel>
The ItemsControl
<StatusBarItem>
The ListBox control
<TextBlock Name="lblCursorPosition" />
The ComboBox control
</StatusBarItem>
<Separator Grid.Column="1" />
<StatusBarItem Grid.Column="2">
<TextBlock The ListView control
Text="c:\path\of\current\file.txt" /> Introduction
</StatusBarItem> A simple ListView
<Separator Grid.Column="3" /> ListView, data binding and
<StatusBarItem Grid.Column="4"> ItemTemplate
<ProgressBar Value="50" Width="90" ListView with a GridView
Height="16" /> How-to: Left aligned column
</StatusBarItem> names
</StatusBar> ListView grouping
<TextBox AcceptsReturn="True" Name="txtEditor" ListView sorting
SelectionChanged="txtEditor_SelectionChanged" /> How-to: ListView with
</DockPanel> column sorting
As you can see, I've added a bit of sample information, like the fake filename
in the middle column and the progress bar to the right, showing a static
value
for now. You could easily make this work for real though, and it gives a pretty
good idea on what you can do with the StatusBar control.
Summary
Once again, WPF makes it easy to get standard Windows functionality, in
this case the StatusBar, integrated into your applications.
You can even place other controls than the ones used in these examples,
like buttons, combo boxes and so on, but please be aware that since the
StatusBar
doesn't apply any special rendering to these controls when hosting
them, it might not look as you would expect it to for controls in a status bar.
This can
be handled with custom styling if you need it though, a subject
discussed elsewhere in this tutorial.
Previous Next
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
The Ribbon control
Download this entire
tutorial as PDF right
now!
The Ribbon interface was invented by Microsoft and first used in Office 2007. About WPF
It combines the original menu and toolbar(s) into one control, with various
What is WPF?
functions grouped into tabs and groups. The most important purpose was to
WPF vs. WinForms
make it easier for the user to discover all the functionality, instead of hiding
it
in long menus. The Ribbon also allows for prioritization of functionality, with
the ability to use different sizes of buttons.
Getting started
Visual Studio Express
Hello, WPF!
XAML
What is XAML?
Basic XAML
WPF doesn't come with a built-in Ribbon control, but Microsoft has released Events in XAML
one that you can download and use for free, as long as you promise to follow
their implementation guide when using it. You can read much more about it
at MSDN,
where you'll also find a download link for the Ribbon control. A WPF application
Introduction
Summary The Window
Working with App.xaml
You can download and use a Microsoft created Ribbon control, but it's not
Command-line parameters
yet a part of the .NET framework by default. Once it becomes an integrated
Resources
part
of the framework, we'll dig into it here at this tutorial. In the meantime, if
Handling exceptions
you're looking for a more complete Ribbon implementation, you might want to
look at some 3rd party alternatives - there are plenty of them, from some of
the big WPF control vendors.
Basic controls
Previous Next The TextBlock control
The TextBlock control - Inline
formatting
The Label control
comments powered by Disqus
The TextBox control
The CheckBox control
Panels
Introduction to WPF Panels
The Canvas
The WrapPanel
The StackPanel
The DockPanel
The Grid
The Grid - Rows & Columns
The Grid - Units
The Grid - Spanning
The Grid - GridSplitter
Using the Grid: A contact
form
Data binding
Introduction
Hello, bound world!
Using the DataContext
The UpdateSourceTrigger
property
Responding to changes
Value conversion with
IValueConverter
The StringFormat property
Debugging data bindings
Commands
Introduction
Using commands
Implementing custom
commands
Common interface
controls
The Menu control
The ContextMenu
The ToolBar control
The StatusBar control
The Ribbon Control
Introduction
The
FlowDocumentScrollViewer
control
The
FlowDocumentPageViewer
control
The FlowDocumentReader
control
Creating a FlowDocument
from Code-behind
Advanced FlowDocument
content
The RichTextBox control
Misc. controls
The Border control
The Slider control
The ProgressBar control
The WebBrowser control
The WindowsFormsHost
control
The TabControl
Using the TabControl
Tab positions
Styling the TabItems
List controls
The ItemsControl
The ListBox control
The ComboBox control
ListView filtering
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
Introduction to WPF Rich Text controls
Download this entire
tutorial as PDF right
now!
In other UI frameworks like WinForms, displaying large amounts of richly About WPF
formatted text has been somewhat of a problem. Sure, you could load a file
What is WPF?
into a
RichTextBox or you could create a WebBrowser object and load a local
WPF vs. WinForms
or remote web page, but specifying larger amounts of rich text in design-time
wasn't
really possible. It seems that Microsoft wanted to remedy that in WPF
and even go beyond just simple viewing of the text.
Getting started
The FlowDocument does indeed render rich text, and that even includes Visual Studio Express
images, lists and tables, and elements can be floated, adjusted and so on, Hello, WPF!
and using
a FlowDocument, you can specify rich text in design-time as if it
were HTML (thanks to XAML) and have it rendered directly in your WPF
application.
XAML
The FlowDocument doesn't stand alone. Instead, it uses one of several built- What is XAML?
in wrappers, which controls how the FlowDocument is laid out and whether Basic XAML
the
content can be edited by the user or not. WPF includes three controls for Events in XAML
rendering a FlowDocument in read-only mode, which all has easy support for
zooming and printing:
A WPF application
FlowDocumentScrollViewer
- the simplest wrapper around a
Introduction
FlowDocument, which simply displays the document as one long document
The Window
of text which you can scroll in.
Working with App.xaml
FlowDocumentPageViewer
- this wrapper will automatically split your Command-line parameters
document into pages, which the user can navigate back and forth between. Resources
Handling exceptions
FlowDocumentReader
- a combination of the FlowDocumentScrollViewer
and the FlowDocumentPageViewer, which will let the user decide between
the two rendering
modes. It also offers the ability AND the interface to search Basic controls
in the document. The TextBlock control
The TextBlock control - Inline
The FlowDocument is normally read-only, but put it inside of a RichTextBox
formatting
control (described later in this tutorial) and you can now edit
the text, much
The Label control
like in real word processors like Microsoft Word.
The TextBox control
Read on through the next chapters, where we'll discuss all the wrappers that The CheckBox control
you can use with a FlowDocument, both read-only and editable. After that, The RadioButton control
we'll look into all of the possibilities you have when creating rich documents The PasswordBox control
using the FlowDocument, including tables, lists, images and much more.
Data binding
Introduction
Hello, bound world!
Using the DataContext
The UpdateSourceTrigger
property
Responding to changes
Value conversion with
IValueConverter
The StringFormat property
Debugging data bindings
Commands
Introduction
Using commands
Implementing custom
commands
Common interface
controls
The Menu control
The ContextMenu
The ToolBar control
The StatusBar control
The Ribbon Control
Introduction
The
FlowDocumentScrollViewer
control
The
FlowDocumentPageViewer
control
The FlowDocumentReader
control
Creating a FlowDocument
from Code-behind
Advanced FlowDocument
content
The RichTextBox control
Misc. controls
The Border control
The Slider control
The ProgressBar control
The WebBrowser control
The WindowsFormsHost
control
The TabControl
Using the TabControl
Tab positions
Styling the TabItems
List controls
The ItemsControl
The ListBox control
The ComboBox control
ListView filtering
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
The FlowDocumentScrollViewer
control Download this entire
tutorial as PDF right
now!
About WPF
In the range of FlowDocument wrappers, discussed in the introduction, the
What is WPF?
FlowDocumentScrollViewer is the simplest one. It simply allows the users to
WPF vs. WinForms
scroll to long documents, using regular scrollbars. Since this is our first
meeting with the FlowDocument used in any form, we'll start off with a basic
"Hello World!" example, and besides the use of FlowDocumentScrollViewer,
this article will also cover several concepts common between all of the Getting started
wrappers.
Here's the first example: Visual Studio Express
Hello, WPF!
<Window
x:Class="WpfTutorialSamples.Rich_text_controls.FlowDocumentS
XAML
What is XAML?
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta Basic XAML
Events in XAML
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="FlowDocumentScrollViewerSample"
A WPF application
Height="200" Width="300">
Introduction
<Grid>
The Window
<FlowDocumentScrollViewer>
Working with App.xaml
<FlowDocument>
Command-line parameters
<Paragraph FontSize="36">Hello, world!
Resources
</Paragraph>
Handling exceptions
<Paragraph FontStyle="Italic"
TextAlignment="Left" FontSize="14" Foreground="Gray">The
ultimate programming greeting!</Paragraph>
</FlowDocument> Basic controls
</FlowDocumentScrollViewer> The TextBlock control
</Grid> The TextBlock control - Inline
</Window> formatting
The Label control
The TextBox control
The CheckBox control
Panels
Introduction to WPF Panels
The Canvas
The WrapPanel
The StackPanel
The DockPanel
Notice how easy it was to specify the text, using simple markup tags, in this The Grid
case the Paragraph tag. Now you might argue that this could
have been The Grid - Rows & Columns
achieved with a couple of TextBlock controls, and you would be absolutely The Grid - Units
right, but even with an extremely basic example like this, you get a
bit of The Grid - Spanning
added functionality for free: You can select the text and copy it to the The Grid - GridSplitter
clipboard. It'll look like this: Using the Grid: A contact
form
Data binding
Introduction
Hello, bound world!
Using the DataContext
The UpdateSourceTrigger
property
Responding to changes
Value conversion with
IValueConverter
Zooming and scrollbar visibility The StringFormat property
Debugging data bindings
As previously mentioned, all of the FlowDocument wrappers support zooming
out of the box. With the example above, you can simply hold down the Ctrl
key
while using the mouse wheel to zoom in and out. This might not be
obvious to your end users though, so you can help them by displaying the
Commands
built-in toolbar
of the FlowDocumentScrollViewer, which has controls that will Introduction
allow you to change the zoom level. Just set the IsToolBarVisible property Using commands
to true on the FlowDocumentScrollViewer, and you're good to go, as you can Implementing custom
see in the next example: commands
<Window
x:Class="WpfTutorialSamples.Rich_text_controls.FlowDocumentS Common interface
controls
The Menu control
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta The ContextMenu
The ToolBar control
The StatusBar control
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" The Ribbon Control
Title="FlowDocumentScrollViewerZoomSample"
Height="180" Width="300">
Misc. controls
The Border control
The Slider control
The ProgressBar control
The WebBrowser control
The WindowsFormsHost
control
Now the user can control the zoom level using the slider and the buttons in
the toolbar below the document. Notice also that we changed the default
zoom
level, using the Zoom property - it defines the zoom level in
The TabControl
percentages, so in this case, the text is zoomed out to 80% by default. Using the TabControl
Tab positions
The last thing I changed in this example, in comparison to the first one, is the Styling the TabItems
use of the ScrollViewer.VerticalScrollBarVisibility
property. By setting it to
Auto, the scrollbars will be invisible until the content actually goes beyond
the available space, which is
usually what you want. List controls
Text alignment The ItemsControl
The ListBox control
You may have noticed that I specifically used the TextAlignment property in The ComboBox control
the above examples. That's because the text is rendered
justified by default,
in a WPF FlowDocument, meaning that each line of text is stretched to cover
the entire available width, if needed. As you can see,
this can be changed, The ListView control
either on a single paragraph or globally for the entire document by setting the
Introduction
same property on the FlowDocument element.
A simple ListView
ListView, data binding and
However, in many situations, justified text makes sense, but it can result in
ItemTemplate
some very bad layout, with very excessive amounts of whitespace on lines
ListView with a GridView
where a linebreak is inserted right before a very long word.
How-to: Left aligned column
The following example will illustrate that, as well as provide a solution that will names
help remedy the problem. By using the IsOptimalParagraphEnabled ListView grouping
property in combination with the IsHyphenationEnabled property, you will ListView sorting
give WPF a better
chance of laying out the text in the best possible way. How-to: ListView with
column sorting
IsOptimalParagraphEnabled
allows WPF to look ahead in your text, to see if ListView filtering
it would make more sense to break the text in a different position than right at
the moment where it runs
out of space. IsHyphenationEnabled allows WPF
to split your words with a hyphen, if it would allow for a more natural layout of The TreeView control
the text.
Introduction
A simple TreeView
In the next example, I've rendered the same text twice - one without these
TreeView, data binding and
properties, and one with. The difference is quite obvious:
multiple templates
Handling
<Window
Selection/Expansion state
x:Class="WpfTutorialSamples.Rich_text_controls.FlowDocumentT
Lazy loading TreeView items
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
The DataGrid control
Introduction
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Custom columns
Title="FlowDocumentTextAlignmentSample" Details row
Height="400" Width="330">
<StackPanel>
<FlowDocumentScrollViewer Styles
ScrollViewer.VerticalScrollBarVisibility="Auto"> Introduction
<FlowDocument> Using styles
<Paragraph FontStyle="Italic" Triggers
FontSize="14" Foreground="Gray"> Multi triggers
By setting the Trigger animations
<Bold>IsOptimalParagraphEnabled</Bold>
property to true,
you will allow WPF to look ahead on
Misc.
the lines to come, before deciding
where to break. This will usually The DispatcherTimer
result in a more pleasant reading
experience. It works especially well
in combination with the Audio & Video
<Bold>IsHyphenationEnabled</Bold> Playing audio
property. Playing video
</Paragraph> How-to: Complete media
</FlowDocument> player
</FlowDocumentScrollViewer> Speech synthesis
<FlowDocumentScrollViewer Speech recognition
ScrollViewer.VerticalScrollBarVisibility="Auto">
<FlowDocument IsOptimalParagraphEnabled="True"
IsHyphenationEnabled="True">
<Paragraph FontStyle="Italic"
FontSize="14" Foreground="Gray">
By setting the
<Bold>IsOptimalParagraphEnabled</Bold> property to true,
you will allow WPF to look ahead on
the lines to come, before deciding
where to break. This will usually
IsOptimalParagraphEnabled is not enabled by default because it does
require a bit more CPU power when rendering the text, especially if the
window is
frequently resized. For most situations this shouldn't be a problem
though.
If you have a lot of FlowDocument instances in your application and you
prefer this optimal rendering method, you can enable it on all of your
FlowDocument
instances by specifying a global style that enables it, in your
App.xaml. Here's an example:
<Application x:Class="WpfTutorialSamples.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-
namespace:System;assembly=mscorlib"
StartupUri="Rich text
controls/FlowDocumentTextAlignmentSample.xaml">
<Application.Resources>
<Style TargetType="FlowDocument">
<Setter Property="IsOptimalParagraphEnabled"
Value="True" />
<Setter Property="IsHyphenationEnabled"
Value="True" />
</Style>
</Application.Resources>
</Application>
Previous Next
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
The FlowDocumentPageViewer control
Download this entire
tutorial as PDF right
now!
In the previous article, we discussed the FlowDocumentScrollViewer, along About WPF
with some more general FlowDocument related techniques. In this article,
What is WPF?
we'll
focus on the FlowDocumentPageViewer which, instead of just offering
WPF vs. WinForms
a scroll text when the text gets longer than the available space,
divides the
entire document up into pages. This allows you to navigate from page to
page, giving a more book-like reading experience.
Getting started
We'll start off with a simple example, where we can see how the Visual Studio Express
FlowDocumentPageViewer control handles our Lorem Ipsum test text: Hello, WPF!
<Window
x:Class="WpfTutorialSamples.Rich_text_controls.FlowDocumentP XAML
What is XAML?
Basic XAML
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
Events in XAML
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
A WPF application
Title="FlowDocumentPageViewerSample" Height="300"
Width="300"> Introduction
<Grid> The Window
<FlowDocumentPageViewer> Working with App.xaml
<FlowDocument> Command-line parameters
<Paragraph>Lorem ipsum dolor sit amet, Resources
consectetur adipiscing elit. Fusce faucibus odio arcu, Handling exceptions
luctus vestibulum tortor congue in. Lorem ipsum dolor sit
amet, consectetur adipiscing elit. Fusce nec lacinia
neque. Donec malesuada, ligula non vestibulum cursus, urna Basic controls
purus pellentesque orci, aliquet accumsan dui velit ac The TextBlock control
justo. Phasellus sagittis ligula in leo dapibus, vel The TextBlock control - Inline
vestibulum felis mattis. Fusce vitae auctor nibh. Ut sit formatting
amet fringilla turpis. Aenean tincidunt feugiat sapien, The Label control
quis scelerisque enim pretium commodo. Mauris fermentum The TextBox control
posuere nulla, vitae fermentum quam malesuada in. Cras The CheckBox control
ultrices bibendum nulla eu mollis. Sed accumsan pretium
Commands
Introduction
Using commands
Implementing custom
commands
Common interface
Notice how the long text is cut off, and in the bottom, you can navigate controls
between pages. This is not all that the FlowDocumentPageViewer will do for The Menu control
you
though - just look what happens when we make the window wider: The ContextMenu
The ToolBar control
The StatusBar control
The Ribbon Control
Introduction
The
FlowDocumentScrollViewer
control
The
Instead of just stretching the text indefinitely, the FlowDocumentPageViewer FlowDocumentPageViewer
now divides your text up into columns, to prevent lines from becoming too control
long. Besides looking good, this also increases the readability, as texts with The FlowDocumentReader
very long lines are harder to read. The page count is of course
automatically control
adjusted, bringing the amount of pages down from 5 to 2. Creating a FlowDocument
from Code-behind
The FlowDocument class has a range of properties that will allow you to
Advanced FlowDocument
control how and when they are used. Using them is simple, but a complete
content
example
goes beyond the scope of this tutorial. Instead, have a look at this
The RichTextBox control
MSDN article, where several properties are used in a nice example: How to:
Use FlowDocument Column-Separating Attributes.
Misc. controls
Searching
The Border control
As you're about to see in the next chapter, the FlowDocumentReader The Slider control
wrapper supports searching right out of the box, with search controls in the The ProgressBar control
toolbar and
everything. However, all of the three read-only FlowDocument The WebBrowser control
wrappers which will be discussed in this tutorial does in fact support The WindowsFormsHost
searching, it just has
to be manually invoked for the first two control
(FlowDocumentScrollViewer and FlowDocumentPageViewer).
All three viewers support the Ctrl+F keyboard shortcut for initiating a search,
The TabControl
but if you want this to be accessible from e.g. a button
as well, you just have
to call the Find() method. Here's an example: Using the TabControl
Tab positions
Styling the TabItems
<Window
x:Class="WpfTutorialSamples.Rich_text_controls.FlowDocumentS
List controls
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta The ItemsControl
The ListBox control
The ComboBox control
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="FlowDocumentSearchSample" Height="300"
Width="580"> The ListView control
<DockPanel>
Introduction
<WrapPanel DockPanel.Dock="Top">
A simple ListView
<Button Name="btnSearch"
ListView, data binding and
Click="btnSearch_Click">Search</Button>
ItemTemplate
</WrapPanel>
ListView with a GridView
<FlowDocumentPageViewer Name="fdViewer">
using System;
using System.Windows; Audio & Video
Playing audio
namespace WpfTutorialSamples.Rich_text_controls Playing video
{ How-to: Complete media
public partial class FlowDocumentSearchSample : player
Window Speech synthesis
{ Speech recognition
public FlowDocumentSearchSample()
{
InitializeComponent();
}
Simply press our dedicated Search button or the keyboard shortcut (Ctrl+F)
and you have search functionality in the
FlowDocumentPageViewer. As
mentioned, this works for both FlowDocumentScrollViewer and
FlowDocumentPageViewer (FlowDocumentPageReader has a search button
by default), but make sure that the search box has enough horizontal
room on the toolbar - otherwise you won't see it when you invoke the
Find()
command!
Previous Next
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
The FlowDocumentReader control
Download this entire
tutorial as PDF right
now!
The FlowDocumentReader is definitely the most advanced read-only About WPF
wrapper that you can place around a FlowDocument. It offers buttons that
What is WPF?
allows the end user to toggle between the rendering modes offered by the
WPF vs. WinForms
FlowDocumentScrollViewer and the FlowDocumentPageViewer, as well as
out-of-the-box
document searching and of course controls for zooming in and
out.
Getting started
All of this functionality also makes the FlowDocumentReader the heaviest of Visual Studio Express
the three read-only wrappers, but this should hardly be an issue with most Hello, WPF!
regularly sized documents. Here's an example of how the
FlowDocumentReader might look:
XAML
What is XAML?
Basic XAML
Events in XAML
A WPF application
Introduction
The Window
Working with App.xaml
This screenshot is taken in the page-based view, which is the default. You Command-line parameters
can switch between the view modes using the buttons to the left of the zoom Resources
controls. In the left part of the toolbar, you have the controls for searching Handling exceptions
through the document, as I have done here on the screenshot.
Here's the code that will give you the above result: Basic controls
The TextBlock control
<Window The TextBlock control - Inline
x:Class="WpfTutorialSamples.Rich_text_controls.FlowDocumentR formatting
The Label control
The TextBox control
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta The CheckBox control
Introduction
The
FlowDocumentScrollViewer
control
The
FlowDocumentPageViewer
control
The FlowDocumentReader
control
Creating a FlowDocument
from Code-behind
The FlowDocumentReader has a range of properties that can help you in
Advanced FlowDocument
controlling how it works. Here's an incomplete list of some of the most
content
important
ones:
The RichTextBox control
ViewingMode
- controls the initial viewing mode. The default is Page, but you
can change that into Scroll or TwoPage
, if you want another default view.
This can still be changed by the user, unless specifically disabled. Misc. controls
The Border control
IsFindEnabled
- gives you the ability to disable searching in the document. If The Slider control
disabled, the search button will be removed from the toolbar. The ProgressBar control
The WebBrowser control
IsTwoPageViewEnabled
, IsPageViewEnabled and IsScrollViewEnabled -
The WindowsFormsHost
allows you to turn off a specific viewing mode for the reader. When set to
control
false, this mode is no longer available for the reader and the button is
removed from the toolbar.
Zoom
- allows you to set the default zoom level. The standard is 100%, but The TabControl
you can change this by using the Zoom property. Using the TabControl
Tab positions
Summary Styling the TabItems
We've now been through all the choices for a read-only FlowDocument
wrapper, and as you can probably see, which one to choose really depends
on the task at
hand. List controls
The ItemsControl
If you just want simple FlowDocument rendering with a scrollbar you should The ListBox control
go with the FlowDocumentScrollViewer - it's simple and is the least space The ComboBox control
and
resource consuming of the three. If you want a paged view, go with the
FlowDocumentPageViewer, unless you want your user to be able to switch
between the
modes and be able to quickly search, in which case you should The ListView control
use the FlowDocumentReader.
Introduction
A simple ListView
Previous Next ListView, data binding and
ItemTemplate
ListView with a GridView
How-to: Left aligned column
comments powered by Disqus names
ListView grouping
ListView sorting
How-to: ListView with
column sorting
ListView filtering
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
Creating a FlowDocument from Code-
behind Download this entire
tutorial as PDF right
now!
About WPF
So far, we've been creating our FlowDocument's directly in XAML.
What is WPF?
Representing a document in XAML makes sense, because XAML is so much
WPF vs. WinForms
like HTML, which is
used all over the Internet to create pages of information.
However, this obviously doesn't mean that you can't create FlowDocument's
from Code-behind - you
absolutely can, since every element is represented
by a class that you can instantiate and add with good, old C# code. Getting started
Visual Studio Express
As a bare minimum example, here's our "Hello, world!" example from one of Hello, WPF!
the first articles, created from Code-behind instead of XAML:
<Window XAML
x:Class="WpfTutorialSamples.Rich_text_controls.CodeBehindFlo
What is XAML?
Basic XAML
Events in XAML
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
A WPF application
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="CodeBehindFlowDocumentSample" Height="200" Introduction
Width="300"> The Window
<Grid> Working with App.xaml
<FlowDocumentScrollViewer Name="fdViewer" /> Command-line parameters
</Grid> Resources
</Window> Handling exceptions
Basic controls
using System;
The TextBlock control
using System.Windows;
The TextBlock control - Inline
using System.Windows.Documents;
formatting
using System.Windows.Media;
The Label control
The TextBox control
namespace WpfTutorialSamples.Rich_text_controls
The CheckBox control
{
Commands
Introduction
Using commands
Implementing custom
commands
Common interface
When compared to the small amount of XAML required to achieve the exact
controls
same thing, this is hardly impressive:
The Menu control
The ContextMenu
<FlowDocument>
The ToolBar control
<Paragraph FontSize="36">Hello, world!</Paragraph>
The StatusBar control
<Paragraph FontStyle="Italic" TextAlignment="Left"
The Ribbon Control
FontSize="14" Foreground="Gray">The ultimate programming
greeting!</Paragraph>
</FlowDocument>
Rich Text controls
Introduction
That's beside the point here though - sometimes it just makes more sense to
The
handle stuff from Code-behind, and as you can see, it's definitely possible.
FlowDocumentScrollViewer
control
Previous Next The
FlowDocumentPageViewer
control
The FlowDocumentReader
comments powered by Disqus control
Creating a FlowDocument
from Code-behind
Advanced FlowDocument
content
The RichTextBox control
Misc. controls
The Border control
The Slider control
The ProgressBar control
The WebBrowser control
The WindowsFormsHost
control
The TabControl
Using the TabControl
Tab positions
Styling the TabItems
List controls
The ItemsControl
The ListBox control
The ComboBox control
ListView filtering
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
Advanced FlowDocument content
Download this entire
tutorial as PDF right
now!
As I already mentioned, the text presentation capabilities of WPF and the About WPF
FlowDocument is very rich - you can do almost anything, and this includes
What is WPF?
stuff
like lists, images and even tables. So far, we've used very basic
WPF vs. WinForms
examples of FlowDocument content, but in this article, we'll finally do a more
comprehensive example.
The XAML code for the next example might look a bit overwhelming, but Getting started
notice how simple it actually is - just like HTML, you can format text simply by Visual Studio Express
placing them in styled paragraphs. Now have a look at the XAML. A Hello, WPF!
screenshot of the result will follow directly after it:
<Window XAML
x:Class="WpfTutorialSamples.Rich_text_controls.ExtendedFlowD
What is XAML?
Basic XAML
Events in XAML
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
A WPF application
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ExtendedFlowDocumentSample" Height="550" Introduction
Width="500"> The Window
<Grid> Working with App.xaml
<FlowDocumentScrollViewer> Command-line parameters
<FlowDocument> Resources
<Paragraph> Handling exceptions
<Image Source="http://www.wpf-
tutorial.com/images/logo.png" Width="90" Height="90"
Margin="0,0,30,0" /> Basic controls
<Run FontSize="120">WPF</Run> The TextBlock control
</Paragraph> The TextBlock control - Inline
formatting
<Paragraph> The Label control
WPF, which stands for The TextBox control
<Bold>Windows Presentation The CheckBox control
Foundation</Bold>,
<TableCell>
Introduction
<Paragraph
The
TextAlignment="Right">1.718.000</Paragraph>
FlowDocumentScrollViewer
</TableCell>
control
<TableCell>
The
<Paragraph
FlowDocumentPageViewer
TextAlignment="Right">1.542.000</Paragraph>
control
</TableCell>
The FlowDocumentReader
</TableRow>
control
</TableRowGroup>
Creating a FlowDocument
<TableRowGroup>
from Code-behind
<TableRow>
Advanced FlowDocument
<TableCell
content
Background="Gainsboro" FontWeight="Bold">
The RichTextBox control
<Paragraph>Developers</Paragraph>
</TableCell>
Misc. controls
<TableCell>
<Paragraph The Border control
TextAlignment="Right">633.000</Paragraph> The Slider control
</TableCell> The ProgressBar control
<TableCell> The WebBrowser control
<Paragraph The WindowsFormsHost
TextAlignment="Right">981.000</Paragraph> control
</TableCell>
</TableRow>
</TableRowGroup> The TabControl
</Table> Using the TabControl
<Paragraph Foreground="Silver" Tab positions
FontStyle="Italic">A table of made up WinForms/WPF Styling the TabItems
numbers</Paragraph>
</FlowDocument>
</FlowDocumentScrollViewer>
List controls
</Grid>
The ItemsControl
</Window>
The ListBox control
The ComboBox control
ListView filtering
I'm not going to go too much into details about each of the tags - hopefully
they should make sense as they are. The DataGrid control
Introduction
As you can see, including lists, images and tables are pretty easy, but in fact, Custom columns
you can include any WPF control inside of your FlowDocument. Using the Details row
BlockUIContainer element you get access to all controls that would otherwise
only be available inside of a window. Here's an example:
Styles
<Window
Introduction
x:Class="WpfTutorialSamples.Rich_text_controls.BlockUIContai
Using styles
Triggers
Multi triggers
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
Trigger animations
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Misc.
xmlns:self="clr-
namespace:WpfTutorialSamples.Rich_text_controls" The DispatcherTimer
Title="BlockUIContainerSample" Height="275"
Width="300">
<Window.Resources> Audio & Video
<x:Array x:Key="UserArray" Type="{x:Type Playing audio
self:User}"> Playing video
<self:User Name="John Doe" Age="42"/> How-to: Complete media
Now we have a FlowDocument with a ListView inside of it, and as you can
see from the screenshot, the ListView works just like it normally would,
including
selections etc. Pretty cool!
Summary
By using the techniques described in the two examples of this article, pretty
much anything is possible, when creating FlowDocument documents. It's
excellent for presenting visual information to the end-user, as seen in many
of the expensive reporting suites.
Previous Next
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
The RichTextBox control
Download this entire
tutorial as PDF right
now!
So far, we've only looked at the read-only wrappers for the FlowDocument, About WPF
but WPF also includes a control which makes a FlowDocument editable: The
What is WPF?
RichTextBox control.
WPF vs. WinForms
You can add a RichTextBox directly to the window, without any content - in
that case, it will automatically create a FlowDocument instance that you will
be
editing. Alternatively, you can wrap a FlowDocument instance with the Getting started
RichTextBox and thereby control the initial content. It could look like this: Visual Studio Express
Hello, WPF!
<Window
x:Class="WpfTutorialSamples.Rich_text_controls.RichTextBoxSa
XAML
What is XAML?
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
Basic XAML
Events in XAML
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="RichTextBoxSample" Height="200"
A WPF application
Width="300">
<Grid> Introduction
<RichTextBox Margin="10"> The Window
<FlowDocument> Working with App.xaml
<Paragraph FontSize="36">Hello, world! Command-line parameters
</Paragraph> Resources
<Paragraph FontStyle="Italic" Handling exceptions
TextAlignment="Left" FontSize="14"
Foreground="Gray">Thanks to the RichTextBox control, this
FlowDocument is completely editable!</Paragraph> Basic controls
</FlowDocument> The TextBlock control
</RichTextBox> The TextBlock control - Inline
</Grid> formatting
</Window> The Label control
The TextBox control
The CheckBox control
Panels
Introduction to WPF Panels
The Canvas
The WrapPanel
The StackPanel
The DockPanel
The Grid
With this example, you can start editing your rich text content straight away. The Grid - Rows & Columns
However, now that the content is no longer read-only, it's obviously The Grid - Units
interesting how you can manipulate the text, as well as work with the The Grid - Spanning
selection. We'll look into that right now. The Grid - GridSplitter
Using the Grid: A contact
Another interesting aspect is of course working with the various formatting
form
possibilities - we'll look into that in the next article, where we actually
implement a small, but fully functional rich text editor.
Data binding
Working with text and selection
Introduction
Because the RichTextBox uses a FlowDocument internally, and because the Hello, bound world!
rich text format is obviously more complicated than plain text, working with Using the DataContext
text
and selections are not quite as easy as for the WPF TextBox control. The UpdateSourceTrigger
property
The next example will provide show off a range of functionality that works
Responding to changes
with the text and/or selection in the RichTextBox control:
Value conversion with
IValueConverter
<Window The StringFormat property
x:Class="WpfTutorialSamples.Rich_text_controls.RichTextBoxTe Debugging data bindings
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
Commands
Introduction
Using commands
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Implementing custom
Title="RichTextBoxTextSelectionSample"
commands
Height="300" Width="400">
<DockPanel>
<WrapPanel DockPanel.Dock="Top">
<Button Name="btnGetText" Common interface
Click="btnGetText_Click">Get text</Button> controls
<Button Name="btnSetText" The Menu control
Click="btnSetText_Click">Set text</Button> The ContextMenu
<Button Name="btnGetSelectedText" The ToolBar control
Click="btnGetSelectedText_Click">Get sel. text</Button> The StatusBar control
<Button Name="btnSetSelectedText" The Ribbon Control
Click="btnSetSelectedText_Click">Replace sel.
text</Button>
</WrapPanel> Rich Text controls
Misc. controls
using System; The Border control
using System.Windows; The Slider control
using System.Windows.Controls; The ProgressBar control
using System.Windows.Documents; The WebBrowser control
The WindowsFormsHost
namespace WpfTutorialSamples.Rich_text_controls control
{
public partial class
RichTextBoxTextSelectionSample : Window
The TabControl
{
public RichTextBoxTextSelectionSample() Using the TabControl
{ Tab positions
InitializeComponent(); Styling the TabItems
}
ListView filtering
private void
btnGetSelectedText_Click(object sender, RoutedEventArgs e)
{
The TreeView control
MessageBox.Show(rtbEditor.Selection.Text); Introduction
} A simple TreeView
TreeView, data binding and
private void multiple templates
btnSetSelectedText_Click(object sender, RoutedEventArgs e) Handling
{ Selection/Expansion state
rtbEditor.Selection.Text = " Lazy loading TreeView items
[Replaced text]";
}
The DataGrid control
private void
Introduction
rtbEditor_SelectionChanged(object sender, RoutedEventArgs
Custom columns
e)
Details row
{
TextRange tempRange = new
TextRange(rtbEditor.Document.ContentStart,
Styles
rtbEditor.Selection.Start);
txtStatus.Text = "Selection starts Introduction
at character #" + tempRange.Text.Length + Using styles
Environment.NewLine; Triggers
txtStatus.Text += "Selection is " Multi triggers
+ rtbEditor.Selection.Text.Length + " character(s) long" + Trigger animations
Environment.NewLine;
txtStatus.Text += "Selected text:
'" + rtbEditor.Selection.Text + "'"; Misc.
} The DispatcherTimer
}
}
As you can see, the markup consists of a panel of buttons, a RichTextBox
and a TextBox in the bottom, to show the current selection status. Each of
the
four available buttons will work with the RichTextBox by either getting or
setting/replacing text, to show you how that's done.
In Code-behind, we handle the four buttons click events, as well as the
SelectionChanged event for the RichTextBox, which allows us to show
statistics
about the current selection.
Pay special attention to the fact that instead of accessing a text property
directly on the RichTextBox, as we would do with a regular TextBox, we're
using
TextRange objects with TextPointer's from the RichTextBox to obtain
text from the control or the selection in the control. This is simply how it works
with
RichTextBox, which, as already mentioned, doesn’t work like a regular
TextBox in several aspects.
Paragraph spacing
Another thing you may have noticed when working with the RichTextBox, is
the fact that when you press Enter to start a new paragraph, this paragraph
will
leave an empty line between the old and the new paragraph. Allow me to
illustrate with a screenshot, where I've entered three lines of text, each just
separated by a single Enter key press:
This is normal behavior for a text editor working in paragraphs, but
depending on how and where you use the RichTextBox, it might be confusing
for your
users that a single Enter press results in such a large amount of
space between the lines.
Fortunately, it's very easy to fix. The extra spaces comes from the fact that
paragraphs have a default margin bigger than zero, so fixing it is as simple
as changing this property, which we can do with a style, like this:
<Window
x:Class="WpfTutorialSamples.Rich_text_controls.RichTextBoxPa
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="RichTextBoxParagraphSpacingSample"
Height="150" Width="300">
<Grid>
<RichTextBox Margin="10">
<RichTextBox.Resources>
<Style TargetType="{x:Type Paragraph}">
<Setter Property="Margin" Value="0" />
</Style>
</RichTextBox.Resources>
</RichTextBox>
</Grid>
</Window>
Now the lines don't have extra space around them, and if you want, you can
place the style in the window or even in App.xaml, if you want it to work for
more than just a single RichTextBox.
Summary
The RichTextBox is easy to use, has lots of features straight out of the box,
and can easily be used if you wish to create a fully featured rich text
editor. In
the next article, we'll have a look at doing just that! This will also get us
around important subjects such as loading and saving text from a
RichTextBox and how to affect formatting of text in the control.
Previous Next
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
The Border control
Download this entire
tutorial as PDF right
now!
The Border control is a Decorator control that you may use to draw a border, About WPF
a background, or even both, around another element. Since the WPF panels
What is WPF?
don't
support drawing a border around its edges, the Border control can help
WPF vs. WinForms
you achieve just that, simply by surrounding e.g. a Panel with the Border
control.
A simple example on using the Border as described above could look like Getting started
this: Visual Studio Express
Hello, WPF!
<Window
x:Class="WpfTutorialSamples.Misc_controls.BorderSample"
XAML
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
What is XAML?
Basic XAML
Events in XAML
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="BorderSample" Height="170" Width="200">
<Grid Margin="10">
A WPF application
<Border Background="GhostWhite"
BorderBrush="Gainsboro" BorderThickness="1"> Introduction
<StackPanel Margin="10"> The Window
<Button>Button 1</Button> Working with App.xaml
<Button Command-line parameters
Margin="0,10">Button 2</Button> Resources
<Button>Button 3</Button> Handling exceptions
</StackPanel>
</Border>
</Grid> Basic controls
</Window> The TextBlock control
The TextBlock control - Inline
formatting
The Label control
The TextBox control
The CheckBox control
Panels
Introduction to WPF Panels
The Border is completely lookless until you define either a background or a The Canvas
border brush and thickness, so that's what I've done here, using the The WrapPanel
Background, BorderBrush and BorderThickness properties. The StackPanel
The DockPanel
Border with round corners The Grid
The Grid - Rows & Columns
One of the features I really appreciate about the Border is the fact that it's so The Grid - Units
easy to get round corners. Just look at this slightly modified example,
where The Grid - Spanning
the corners are now rounded: The Grid - GridSplitter
Using the Grid: A contact
<Window form
x:Class="WpfTutorialSamples.Misc_controls.BorderSample"
Common interface
controls
The Menu control
The ContextMenu
The ToolBar control
The StatusBar control
The Ribbon Control
All I've done is adding the CornerRadius property. It can be specified with a Rich Text controls
single value, which will be used for all four corners, or
like I did in the
Introduction
example here, where I specify separate values for the top right and left
The
followed by the bottom right and left.
FlowDocumentScrollViewer
control
Border color/thickness The
The above border is very discrete, but this can easily be changed by FlowDocumentPageViewer
regulating the color and/or thickness. Because the BorderThickness property control
is of the Thickness type, you can even manipulate each of the border widths The FlowDocumentReader
individually or by giving a value for the left and right and one for the
top and control
bottom borders. Creating a FlowDocument
from Code-behind
Advanced FlowDocument
<Window
content
x:Class="WpfTutorialSamples.Misc_controls.BorderSample"
The RichTextBox control
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
Misc. controls
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" The Border control
Title="BorderSample" Height="175" Width="200"> The Slider control
<Grid Margin="10"> The ProgressBar control
<Border Background="GhostWhite" The WebBrowser control
BorderBrush="DodgerBlue" BorderThickness="1,3,1,5"> The WindowsFormsHost
<StackPanel Margin="10"> control
<Button>Button 1</Button>
<Button
Margin="0,10">Button 2</Button> The TabControl
<Button>Button 3</Button>
Using the TabControl
</StackPanel>
Tab positions
</Border>
Styling the TabItems
</Grid>
</Window>
List controls
The ItemsControl
The ListBox control
The ComboBox control
Introduction
A simple ListView
ListView, data binding and
ItemTemplate
Border background ListView with a GridView
How-to: Left aligned column
The Background property is of the type Brush, which opens up a lot of cool names
possibilities. As seen in the initial examples, it's very easy to just use a ListView grouping
simple color as the background, but you can actually use gradients as well, ListView sorting
and it's not even that hard to do: How-to: ListView with
column sorting
<Window ListView filtering
x:Class="WpfTutorialSamples.Misc_controls.BorderSample"
Playing audio
Playing video
How-to: Complete media
player
Speech synthesis
Speech recognition
In this case, I've specified a LinearGradientBrush to be used for the
background of the Border and then a more fitting border color. The
LinearGradientBrush might not have the most obvious syntax, so I will
explain that in a later chapter, including other brush types, but for now, you
can
try my example and change the values to see the result.
Previous Next
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
The Slider control
Download this entire
tutorial as PDF right
now!
The Slider control allows you to pick a numeric value by dragging a thumb About WPF
along a horizontal or vertical line. You see it in a lot of user interfaces, but
it
What is WPF?
can still be a bit hard to recognize from the description alone, so here's a
WPF vs. WinForms
very basic example:
<Window
Getting started
x:Class="WpfTutorialSamples.Misc_controls.SliderSample"
Visual Studio Express
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta Hello, WPF!
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" XAML
Title="SliderSample" Height="100" Width="300"> What is XAML?
<StackPanel VerticalAlignment="Center" Margin="10"> Basic XAML
<Slider Maximum="100" /> Events in XAML
</StackPanel>
</Window>
A WPF application
Introduction
The Window
Working with App.xaml
Command-line parameters
Resources
Handling exceptions
This will allow the end-user to select a value between 0 and 100 by dragging
the button (referred to as the thumb) along the line.
Basic controls
Ticks The TextBlock control
The TextBlock control - Inline
In the example, I have dragged the thumb beyond the middle, but it's formatting
obviously hard to see the exact value. One way to remedy this is to turn on The Label control
ticks,
which are small markers shown on the line to give a better indication on The TextBox control
how far the thumb is. Here's an example: The CheckBox control
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta Panels
Introduction to WPF Panels
The Canvas
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
The WrapPanel
Title="SliderSample" Height="100" Width="300">
The StackPanel
<StackPanel VerticalAlignment="Center" Margin="10">
The DockPanel
<Slider Maximum="100" TickPlacement="BottomRight"
The Grid
TickFrequency="5" />
The Grid - Rows & Columns
</StackPanel>
The Grid - Units
</Window>
The Grid - Spanning
The Grid - GridSplitter
Using the Grid: A contact
form
Data binding
Introduction
Hello, bound world!
I turn on the tick markers by giving the TickPlacement property another
Using the DataContext
value than None, which is the default. In my example, I want the
ticks placed
The UpdateSourceTrigger
below the line, but you can use TopLeft or even Both as possible values, to
property
change this.
Responding to changes
Also notice my use of the TickFrequency property. It defaults to 1, but in an Value conversion with
example where the range of possible values goes from 0 to
100, this will IValueConverter
result in 100 tick markers, which will have to be fitted into the limited space. The StringFormat property
In a case like this, it makes sense to raise the
TickFrequency to something Debugging data bindings
that will make it look less crowded.
Snapping to ticks Commands
Introduction
If you have a look at the screenshot above, you will see that the thumb is
Using commands
between ticks. This makes sense, since there are five values between each
Implementing custom
tick,
as specified by the TickFrequency property. Also, the value of the Slider
commands
control is in fact by default a double, meaning that the value can (and will
likely) be a non-integer. We can change this by using the
IsSnapToTickEnabled property, like in the below example:
Common interface
controls
<Window
x:Class="WpfTutorialSamples.Misc_controls.SliderSnapToTickSa The Menu control
The ContextMenu
The ToolBar control
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta The StatusBar control
The Ribbon Control
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="SliderSnapToTickSample" Height="100" Rich Text controls
Width="300"> Introduction
<StackPanel VerticalAlignment="Center" Margin="10"> The
<Slider Maximum="100" TickPlacement="BottomRight" FlowDocumentScrollViewer
TickFrequency="10" IsSnapToTickEnabled="True" /> control
</StackPanel> The
</Window> FlowDocumentPageViewer
control
The FlowDocumentReader
control
Creating a FlowDocument
from Code-behind
Advanced FlowDocument
content
The RichTextBox control
Notice that I've changed the TickFrequency to 10, and then enabled the
IsSnapToTickEnabled property. This ensures that the thumb can only be
placed
directly on a tick value, so for this example, it can only be 0, 10, 20, Misc. controls
30, 40 and so on.
The Border control
The Slider control
Slider value The ProgressBar control
So far, we've just used the Slider illustratively, but of course, the actual The WebBrowser control
purpose is to read its current value and use it for something. The Slider has
a The WindowsFormsHost
Value property for that, which you can of course read from Code-behind, or control
even bind to.
A common scenario in using the Slider is to combine it with a TextBox, which The TabControl
will allow the user to see the currently selected value, as well as changing
it
Using the TabControl
by entering a number instead of dragging the Slider thumb. Normally, you
Tab positions
would have to subscribe to change events on both the Slider and the
Styling the TabItems
TextBox and
then update accordingly, but a simple binding can do all of that
for us:
List controls
<Window
x:Class="WpfTutorialSamples.Misc_controls.SliderBoundValueSa The ItemsControl
The ListBox control
The ComboBox control
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
Responding to changed values Styles
Introduction
Of course, while bindings are very cool for a lot of purposes, you still may
Using styles
want to respond to changes in the Slider value from your Code-behind.
Triggers
Fortunately for us, the Slider comes with a ValueChanged event which will
Multi triggers
help us with that. To illustrate this, I've created a more complex sample with
Trigger animations
three sliders, where we change the Red, Green and Blue (RGB) values of a
color:
Misc.
<Window
x:Class="WpfTutorialSamples.Misc_controls.SliderValueChanged The DispatcherTimer
using System;
using System.Windows;
using System.Windows.Media;
namespace WpfTutorialSamples.Misc_controls
{
public partial class SliderValueChangedSample :
Window
{
public SliderValueChangedSample()
{
InitializeComponent();
}
private void
ColorSlider_ValueChanged(object sender,
RoutedPropertyChangedEventArgs<double> e)
{
Color color =
Color.FromRgb((byte)slColorR.Value, (byte)slColorG.Value,
(byte)slColorB.Value);
this.Background = new
SolidColorBrush(color);
}
}
}
In the XAML part of the code, we have three DockPanels, each with a Label,
a Slider and a TextBox control. Just like before, the Text property of the
TextBox controls have been bound to the Value of the Slider.
Each slider subscribes to the same ValueChanged event, in which we create
a new Color instance, based on the currently selected values and
then uses
this color to create a new SolidColorBrush for the Background property of the
Window.
All in all, this is a pretty good example of what the Slider control can be used
for.
Previous Next
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
The ProgressBar control
Download this entire
tutorial as PDF right
now!
WPF comes with a handy control for displaying progress, called the About WPF
ProgressBar. It works by setting a minimum and maximum value and then
What is WPF?
incrementing a value, which will give a visual indication on how far in the
WPF vs. WinForms
process you currently are. Here's a very basic example to demonstrate it
with:
Getting started
<Window
x:Class="WpfTutorialSamples.Misc_controls.ProgressBarSample" Visual Studio Express
Hello, WPF!
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
XAML
What is XAML?
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Basic XAML
Title="ProgressBarSample" Height="100" Events in XAML
Width="300">
<Grid Margin="20">
<ProgressBar Minimum="0" Maximum="100" Value="75"
A WPF application
/>
Introduction
</Grid>
The Window
</Window>
Working with App.xaml
Command-line parameters
Resources
Handling exceptions
Basic controls
The TextBlock control
In this case, I've used a pretty standard approach of showing progress as a The TextBlock control - Inline
percentage (between 0 and 100%), giving it an initial value of 75. Another formatting
approach is to use actual minimum and maximum values from a list of tasks The Label control
you're performing. For instance, if you loop through a collected list of files The TextBox control
while checking each of them, you can set the Minimum property to 0, the The CheckBox control
Maximum to the amount of files in your list, and then just increment as you The RadioButton control
loop
through it. The PasswordBox control
The ProgressBar is, just like other standard WPF controls, rendered to match
the visual style of the operating system. Here on Windows 7, it has a nice Panels
animated gradient, as seen on the screenshot.
Introduction to WPF Panels
The Canvas
Showing progress while performing a The WrapPanel
lengthy task The StackPanel
The above example illustrates how simple it is to use a ProgressBar, but The DockPanel
normally you would of course want to show the progress of some actual work The Grid
and not
just a static value. The Grid - Rows & Columns
The Grid - Units
In most situations you will use the ProgressBar to show progress for some The Grid - Spanning
heavy/lengthy task, and this this is where most new programmers run into a The Grid - GridSplitter
very
common problem: If you do a piece of heavy work on the UI thread, Using the Grid: A contact
while trying to simultaneously update e.g. a ProgressBar control, you will form
soon realize
that you can't do both, at the same time, on the same thread. Or
to be more clear, you can, but the ProgressBar won't actually show each
update to the
progress before the task is completed, which pretty much Data binding
renders it useless.
Introduction
To illustrate, you can try the following example: Hello, bound world!
Using the DataContext
The UpdateSourceTrigger
<Window
property
x:Class="WpfTutorialSamples.Misc_controls.ProgressBarTaskOnU
Responding to changes
Value conversion with
IValueConverter
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
The StringFormat property
Debugging data bindings
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ProgressBarTaskOnUiThread" Height="100"
Width="300"
Commands
ContentRendered="Window_ContentRendered"> Introduction
<Grid Margin="20"> Using commands
<ProgressBar Minimum="0" Maximum="100" Implementing custom
Name="pbStatus" /> commands
</Grid>
</Window>
Common interface
controls
using System; The Menu control
using System.Threading; The ContextMenu
using System.Windows; The ToolBar control
The StatusBar control
namespace WpfTutorialSamples.Misc_controls The Ribbon Control
{
public partial class ProgressBarTaskOnUiThread :
Window Rich Text controls
{ Introduction
public ProgressBarTaskOnUiThread() The
{ FlowDocumentScrollViewer
InitializeComponent(); control
} The
FlowDocumentPageViewer
private void Window_ContentRendered(object control
sender, EventArgs e) The FlowDocumentReader
{ control
for(int i = 0; i < 100; i++) Creating a FlowDocument
{ from Code-behind
pbStatus.Value++; Advanced FlowDocument
Thread.Sleep(100); content
} The RichTextBox control
}
}
} Misc. controls
The Border control
A very basic example, where, as soon as the window is ready, we do a loop The Slider control
from 0 to 100 and in each iteration, we increment the value of the The ProgressBar control
ProgressBar.
Any modern computer can do this faster than you can blink The WebBrowser control
your eyes, so I've added a delay to each iteration of 100 milliseconds. The WindowsFormsHost
Unfortunately, as I
already described, nothing will happen. This is how it control
looks in the middle of the process:
The TabControl
Using the TabControl
Tab positions
Styling the TabItems
Notice that the cursor indicates that something is happening, yet the
ProgressBar still looks like it did at the start (empty). As soon as the loop, List controls
which
represents our lengthy task, is done, the ProgressBar will look like this: The ItemsControl
The ListBox control
The ComboBox control
ListView filtering
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
worker.RunWorkerAsync();
}
BackgroundWorker).ReportProgress(i);
Thread.Sleep(100);
}
}
As you can see on the screenshot, the progress is now updated all the way
through the task, and as the cursor indicates, no hard work is being
performed on
the UI thread, which means that you can still interact with the
rest of the interface.
Please be aware that while the BackgroundWorker does help a lot with
multithreading related problems, there are still some things you should be
aware of,
so please have a look at the BackgroundWorker articles in this
tutorial before doing anything more advanced than a scenario like the one
above.
Indeterminate
For some tasks, expressing the progress as a percentage is not possible or
you simply don't know how long it will take. For those situations, the
indeterminate progress bar has been invented, where an animation lets the
user know that something is happening, while indicating that the running time
can't be determined.
The WPF ProgressBar supports this mode through the use of the
IsIndeterminate property, which we'll show you in the next example:
<Window
x:Class="WpfTutorialSamples.Misc_controls.ProgressBarIndeter
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ProgressBarIndeterminateSample"
Height="100" Width="300">
<Grid Margin="20">
<ProgressBar Minimum="0" Maximum="100"
Name="pbStatus" IsIndeterminate="True" />
</Grid>
</Window>
Notice that the green progress indicator is not anchored to either of the sides
- instead it floats freely from start to finish and then it starts all over
again.
ProgressBar with text
One thing that I really missed from the standard WPF ProgressBar is the
ability to show a text representation of the progress as well as the progress
bar.
Fortunately for us, the flexibility of WPF makes this really easy for us to
accomplish. Here's an example:
<Window
x:Class="WpfTutorialSamples.Misc_controls.ProgressBarTextSam
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ProgressBarTextSample" Height="100"
Width="300">
<Grid Margin="20">
<ProgressBar Minimum="0" Maximum="100" Value="75"
Name="pbStatus" />
<TextBlock Text="{Binding ElementName=pbStatus,
Path=Value, StringFormat={}{0:0}%}"
HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</Window>
We accomplish the above by putting the ProgressBar and the TextBlock
showing the percentage inside of the same Grid, without specifying any rows
or
columns. This will render the TextBlock on top of the ProgressBar, which
is exactly what we want here, because the TextBlock has a transparent
background
by default.
We use a binding to make sure that the TextBlock show the same value as
the ProgressBar. Notice the special StringFormat syntax, which
allows us to
show the value with a percentage sign postfix - it might look a bit strange, but
please see the StringFormat article of this
tutorial for more information on it.
Previous Next
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
The WebBrowser control
Download this entire
tutorial as PDF right
now!
WPF comes with a ready to use WebBrowser control, which allows you to About WPF
host a complete web browser within your application. The WebBrowser
What is WPF?
control is really
just a shell around an ActiveX version of Internet Explorer,
WPF vs. WinForms
but since this is an integrated part of Windows, your application should work
on all Windows
machines without requiring the installation of additional
components.
Getting started
I've done things a bit differently in this article: Instead of starting off with a Visual Studio Express
very limited example and then adding to it, I've create just one but
more Hello, WPF!
complex example. It illustrates how easy you can get a small web browser up
and running. It's very basic in its functionality, but you can easily
extend it if
you want to. Here's how it looks:
XAML
What is XAML?
Basic XAML
Events in XAML
A WPF application
Introduction
The Window
Working with App.xaml
Command-line parameters
Resources
Handling exceptions
Basic controls
The TextBlock control
The TextBlock control - Inline
formatting
The Label control
The TextBox control
The CheckBox control
So let's have a look at the code: The RadioButton control
The PasswordBox control
<Window
x:Class="WpfTutorialSamples.Misc_controls.WebBrowserControlS
Panels
Introduction to WPF Panels
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta The Canvas
The WrapPanel
The StackPanel
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" The DockPanel
Title="WebBrowserControlSample" Height="300" The Grid
Width="450"> The Grid - Rows & Columns
<Window.CommandBindings> The Grid - Units
<CommandBinding The Grid - Spanning
Command="NavigationCommands.BrowseBack" The Grid - GridSplitter
CanExecute="BrowseBack_CanExecute" Using the Grid: A contact
Executed="BrowseBack_Executed" /> form
<CommandBinding
Command="NavigationCommands.BrowseForward"
CanExecute="BrowseForward_CanExecute" Data binding
Executed="BrowseForward_Executed" />
Introduction
<CommandBinding
Hello, bound world!
Command="NavigationCommands.GoToPage"
Using the DataContext
CanExecute="GoToPage_CanExecute"
The UpdateSourceTrigger
Executed="GoToPage_Executed" />
property
</Window.CommandBindings>
Responding to changes
<DockPanel>
Value conversion with
<ToolBar DockPanel.Dock="Top">
IValueConverter
<Button
The StringFormat property
Command="NavigationCommands.BrowseBack">
Debugging data bindings
<Image
Source="/WpfTutorialSamples;component/Images/arrow_left.png"
Width="16" Height="16" />
</Button> Commands
<Button Introduction
Command="NavigationCommands.BrowseForward"> Using commands
<Image Implementing custom
Source="/WpfTutorialSamples;component/Images/arrow_right.png commands
Width="16" Height="16" />
</Button>
<Separator /> Common interface
<TextBox Name="txtUrl" Width="300" controls
KeyUp="txtUrl_KeyUp" />
The Menu control
<Button Command="NavigationCommands.GoToPage">
The ContextMenu
<Image
The ToolBar control
Source="/WpfTutorialSamples;component/Images/world_go.png"
The StatusBar control
Width="16" Height="16" />
The Ribbon Control
</Button>
</ToolBar>
<WebBrowser Name="wbSample"
Rich Text controls
Navigating="wbSample_Navigating"></WebBrowser>
</DockPanel> Introduction
</Window> The
FlowDocumentScrollViewer
control
The
using System; FlowDocumentPageViewer
using System.Windows; control
using System.Windows.Input; The FlowDocumentReader
control
namespace WpfTutorialSamples.Misc_controls Creating a FlowDocument
{ from Code-behind
public partial class WebBrowserControlSample : Advanced FlowDocument
Window content
{ The RichTextBox control
public WebBrowserControlSample()
{
InitializeComponent();
Misc. controls
wbSample.Navigate("http://www.wpf-
The Border control
tutorial.com");
The Slider control
}
The ProgressBar control
The WebBrowser control
private void txtUrl_KeyUp(object sender,
The WindowsFormsHost
KeyEventArgs e)
control
{
if(e.Key == Key.Enter)
wbSample.Navigate(txtUrl.Text); The TabControl
} Using the TabControl
Tab positions
private void wbSample_Navigating(object Styling the TabItems
sender,
System.Windows.Navigation.NavigatingCancelEventArgs e)
{ List controls
txtUrl.Text =
The ItemsControl
e.Uri.OriginalString;
The ListBox control
}
The ComboBox control
The code might seem a bit overwhelming at first, but if you take a second Misc.
look, you'll realize that there's a lot of repetition in it. The DispatcherTimer
Let's start off by talking about the XAML part. Notice that I'm using several
concepts discussed elsewhere in this tutorial, including the
ToolBar control
Audio & Video
and WPF commands. The ToolBar is used to host a couple of buttons for
going backward and forward. After that, we have an address bar for
entering Playing audio
and showing the current URL, along with a button for navigating to the Playing video
entered URL. How-to: Complete media
player
Below the toolbar, we have the actual WebBrowser control. As you can see, Speech synthesis
using it only requires a single line of XAML - in this case we subscribe to the Speech recognition
Navigating event, which occurs as soon as the WebBrowser starts
navigating to a URL.
In Code-behind, we start off by navigating to a URL already in the
constructor of the Window, to have something to show immediately
instead of
a blank control. We then have the txtUrl_KeyUp event, in which we check to
see if the user has hit Enter inside of the address
bar - if so, we start
navigating to the entered URL.
The wbSample_Navigating event makes sure that the address bar is
updated each time a new navigation starts. This is important because we
want it to show the current URL no matter if the user initiated the navigation
by entering a new URL or by clicking a link on the webpage.
The last part of the Code-behind is simple handling of our commands: Two
for the back and forward buttons, where we use the CanGoBack and
CanGoForward to
decide whether they can execute, and the GoBack and
GoForward methods to do the actual work. This is very standard when
dealing with WPF commands, as
described in the commands section of this
tutorial.
For the last command, we allow it to always execute and when it does, we
use the Navigate() method once again.
Summary
As you can see, hosting and using a complete webbrowser inside of your
application becomes very easy with the WebBrowser control. However, you
should be
aware that the WPF version of WebBrowser is a bit limited when
compared to the WinForms version, but for basic usage and navigation, it
works fine.
If you wish to use the WinForms version instead, you may do so using the
WindowsFormsHost, which is explained elsewhere in this tutorial.
Previous Next
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
The WindowsFormsHost control
Download this entire
tutorial as PDF right
now!
WPF and WinForms are two distinct UI frameworks, both created by About WPF
Microsoft. WPF is meant as a more modern alternative to WinForms, which
What is WPF?
was the first .NET
UI framework. To lighten the transition between the two,
WPF vs. WinForms
Microsoft has made sure that WinForms controls may still be used inside of a
WPF application. This
is done with the WindowsFormsHost, which we'll
discuss in this article.
Getting started
To use the WindowsFormsHost and controls from WinForms, you need to Visual Studio Express
add a reference to the following assemblies in your application: Hello, WPF!
WindowsFormsIntegration
System.Windows.Forms
XAML
In Visual Studio, this is done by right-clicking the "References" node in your What is XAML?
project and selecting "Add reference": Basic XAML
Events in XAML
A WPF application
Introduction
The Window
Working with App.xaml
Command-line parameters
Resources
Handling exceptions
Basic controls
The TextBlock control
The TextBlock control - Inline
In the dialog that pops up, you should select "Assemblies" and then check
formatting
the two assemblies that we need to add:
The Label control
The TextBox control
The CheckBox control
Panels
Introduction to WPF Panels
The Canvas
The WrapPanel
The StackPanel
The DockPanel
The Grid
The Grid - Rows & Columns
The Grid - Units
The Grid - Spanning
The Grid - GridSplitter
Using the Grid: A contact
form
Using the WinForms WebBrowser control
In a previous article, we used the WPF WebBrowser control to create a small
web browser. However, as stated in that article, the WPF WebBrowser Data binding
control is
a bit limited when compared to the WinForms version. There are Introduction
many examples on things easily done with the WinForms version, which are Hello, bound world!
either harder or
impossible to do with the WPF version. Using the DataContext
The UpdateSourceTrigger
A small example is the DocumentTitle property and corresponding property
DocumentTitleChanged event, which makes it easy to get
and update the Responding to changes
title of the window to match the title of the current webpage. We'll use this as Value conversion with
an excuse to test out the WinForms version right here in
our WPF IValueConverter
application: The StringFormat property
Debugging data bindings
<Window
x:Class="WpfTutorialSamples.Misc_controls.WindowsFormsHostSa
Commands
Introduction
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
Using commands
Implementing custom
commands
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wf="clr-
namespace:System.Windows.Forms;assembly=System.Windows.Forms
Common interface
controls
Title="WindowsFormsHostSample" Height="350"
Width="450"> The Menu control
<Grid> The ContextMenu
<WindowsFormsHost Name="wfhSample"> The ToolBar control
<WindowsFormsHost.Child> The StatusBar control
<wf:WebBrowser The Ribbon Control
DocumentTitleChanged="wbWinForms_DocumentTitleChanged" />
</WindowsFormsHost.Child>
</WindowsFormsHost> Rich Text controls
</Grid> Introduction
</Window> The
FlowDocumentScrollViewer
control
The
using System;
FlowDocumentPageViewer
using System.Windows;
control
The FlowDocumentReader
namespace WpfTutorialSamples.Misc_controls
control
{
Creating a FlowDocument
public partial class WindowsFormsHostSample :
from Code-behind
Window
Advanced FlowDocument
{
content
public WindowsFormsHostSample()
The RichTextBox control
{
InitializeComponent();
(wfhSample.Child as
System.Windows.Forms.WebBrowser).Navigate("http://www.wpf- Misc. controls
tutorial.com"); The Border control
} The Slider control
The ProgressBar control
private void The WebBrowser control
wbWinForms_DocumentTitleChanged(object sender, EventArgs The WindowsFormsHost
e) control
{
this.Title = (sender as
System.Windows.Forms.WebBrowser).DocumentTitle; The TabControl
}
Using the TabControl
}
Tab positions
}
Styling the TabItems
List controls
The ItemsControl
The ListBox control
The ComboBox control
xmlns:wf="clr-
namespace:System.Windows.Forms;assembly=System.Windows.Forms The TreeView control
Introduction
A simple TreeView
TreeView, data binding and
This will allow us to reference WinForms controls using the wf: prefix. multiple templates
Handling
The WindowsFormsHost is fairly simple to use, as you can see. It has a Child Selection/Expansion state
property, in which you can define a single WinForms control, much like the Lazy loading TreeView items
WPF
Window only holds a single root control. If you need more controls from
WinForms inside of your WindowsFormsHost, you can use the Panel
control
from WinForms or any of the other container controls. The DataGrid control
Introduction
The WinForms WebBrowser control is used by referencing the
Custom columns
System.Windows.Forms assembly, using the wf prefix, as explained above.
Details row
In Code-behind, we do an initial call to Navigate, to have a visible webpage
instead of the empty control on startup. We then handle
theDocumentTitleChanged event, in which we update the Title property of Styles
the Window in accordance with the current DocumentTitle value of the Introduction
WebBrowser control. Using styles
Triggers
Congratulations, you now have a WPF application with a WinForms
Multi triggers
WebBrowser hosted inside of it.
Trigger animations
Summary
As you can see, using WinForms controls inside of your WPF applications is Misc.
pretty easy, but the question remains: Is it a good idea? The DispatcherTimer
In general, you may want to avoid it. There are a number of issues that may
or may not affect your application (a lot of them are described in this MSDN
article: http://msdn.microsoft.com/en- Audio & Video
us/library/aa970911%28v=VS.100%29.aspx), but
a more serious problem is Playing audio
that this kind of UI framework mixing might not be supported in future Playing video
versions of the .NET framework. How-to: Complete media
player
In the end though, the decision is up to you - do you really need the Speech synthesis
WinForms control or is there a WPF alternative that might work just as well? Speech recognition
Previous Next
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
Using the WPF TabControl
Download this entire
tutorial as PDF right
now!
The WPF TabControl allows you to split your interface up into different areas, About WPF
each accessible by clicking on the tab header, usually positioned at the top
of
What is WPF?
the control. Tab controls are commonly used in Windows applications and
WPF vs. WinForms
even within Windows' own interfaces, like the properties dialog for
files/folders etc.
Just like with most other WPF controls, the TabControl is very easy to get Getting started
started with. Here's a very basic example: Visual Studio Express
Hello, WPF!
<Window x:Class="WpfTutorialSamples.Misc_controls.TabControlSample"
<Window
XAML
x:Class="WpfTutorialSamples.Misc_controls.TabControlSample"
What is XAML?
Basic XAML
Events in XAML
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
Panels
Introduction to WPF Panels
The Canvas
The WrapPanel
The StackPanel
As you can see, each tab is represented with a TabItem element, where the
The DockPanel
text shown on it is controlled by the Header
property. The TabItem element
The Grid
comes from the ContentControl class, which means that you may define a
The Grid - Rows & Columns
single element inside of it that will be shown if the
tab is active (like on the
The Grid - Units
screenshot). I used a Label in this example, but if you want to place more
The Grid - Spanning
than one control inside of the tab, just use one of
the panels with child
The Grid - GridSplitter
controls inside of it.
Using the Grid: A contact
form
Customized headers
Once again, WPF proves to be extremely flexible when you want to
customize the look of your tabs. Obviously the content can be rendered any Data binding
way you like
it, but so can the tab headers! The Header property can be filled Introduction
with anything you like, which we'll take advantage of in the next example: Hello, bound world!
Using the DataContext
<Window The UpdateSourceTrigger
x:Class="WpfTutorialSamples.Misc_controls.TabControlWithCust property
Responding to changes
Value conversion with
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta IValueConverter
The StringFormat property
Debugging data bindings
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="TabControlWithCustomHeadersSample"
Height="200" Width="250"> Commands
<Grid>
Introduction
<Grid>
Using commands
<TabControl>
Implementing custom
<TabItem>
commands
<TabItem.Header>
<StackPanel
Orientation="Horizontal">
Common interface
<Image
controls
Source="/WpfTutorialSamples;component/Images/bullet_blue.png
/> The Menu control
<TextBlock Text="Blue" The ContextMenu
Foreground="Blue" /> The ToolBar control
</StackPanel> The StatusBar control
</TabItem.Header> The Ribbon Control
<Label Content="Content goes here..."
/>
</TabItem> Rich Text controls
<TabItem> Introduction
<TabItem.Header> The
<StackPanel FlowDocumentScrollViewer
Orientation="Horizontal"> control
<Image The
Source="/WpfTutorialSamples;component/Images/bullet_red.png" FlowDocumentPageViewer
/> control
<TextBlock Text="Red" The FlowDocumentReader
Foreground="Red" /> control
</StackPanel> Creating a FlowDocument
</TabItem.Header> from Code-behind
</TabItem> Advanced FlowDocument
<TabItem> content
<TabItem.Header> The RichTextBox control
<StackPanel
Orientation="Horizontal">
<Image
Misc. controls
Source="/WpfTutorialSamples;component/Images/bullet_green.pn
/> The Border control
<TextBlock Text="Green" The Slider control
Foreground="Green" /> The ProgressBar control
</StackPanel> The WebBrowser control
</TabItem.Header> The WindowsFormsHost
</TabItem> control
</TabControl>
</Grid>
</Grid> The TabControl
</Window> Using the TabControl
Tab positions
Styling the TabItems
List controls
The ItemsControl
The ListBox control
The ComboBox control
Controlling the TabControl How-to: ListView with
Sometimes you may wish to control which tab is selected programmatically column sorting
or perhaps get some information about the selected tab. The WPF ListView filtering
TabControl has
several properties which makes this possible, including
SelectedIndex and SelectedItem. In the next example, I've added a couple of
buttons to the first
example which allows us to control the TabControl: The TreeView control
Introduction
<Window A simple TreeView
x:Class="WpfTutorialSamples.Misc_controls.ControllingTheTabC TreeView, data binding and
multiple templates
Handling
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta Selection/Expansion state
Lazy loading TreeView items
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ControllingTheTabControlSample" The DataGrid control
Height="300" Width="350">
Introduction
<DockPanel>
Custom columns
<StackPanel Orientation="Horizontal"
Details row
DockPanel.Dock="Bottom" Margin="2,5">
<Button Name="btnPreviousTab"
Click="btnPreviousTab_Click">Prev.</Button>
<Button Name="btnNextTab"
Styles
Click="btnNextTab_Click">Next</Button> Introduction
<Button Name="btnSelectedTab" Using styles
Click="btnSelectedTab_Click">Selected</Button> Triggers
</StackPanel> Multi triggers
<TabControl Name="tcSample"> Trigger animations
<TabItem Header="General">
<Label Content="Content goes here..." />
</TabItem> Misc.
<TabItem Header="Security" />
The DispatcherTimer
<TabItem Header="Details" />
</TabControl>
namespace WpfTutorialSamples.Misc_controls
{
public partial class
ControllingTheTabControlSample : Window
{
public ControllingTheTabControlSample()
{
InitializeComponent();
}
As you can see, I've simply added a set of buttons in the lower part of the
interface. The first two allows will select the previous or next tab on the
control, while the last one will display information about the currently selected
tab, as demonstrated on the screenshot.
The first two buttons uses the SelectedIndex property to determine where
we are and then either subtracts or adds one to that value,
making sure that
the new index doesn't fall below or above the amount of available items. The
third button uses the SelectedItem property
to get a reference to the
selected tab. As you can see, I have to typecast it into the TabItem class to
get a hold of the header property, since the
SelectedProperty is of the object
type by default.
Summary
The TabControl is great when you need a clear separation in a dialog or
when there's simply not enough space for all the controls you want in it. In
the next couple of chapters, we'll look into some of the possibilites there are
when using the TabControl for various purposes.
Previous Next
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
WPF TabControl: Tab positions
Download this entire
tutorial as PDF right
now!
The tabs of a TabControl is usually placed on top of the control, which is also About WPF
how it will look by default when using the WPF TabControl:
What is WPF?
WPF vs. WinForms
Getting started
Visual Studio Express
Hello, WPF!
XAML
What is XAML?
Basic XAML
However, using the TabStripPlacement property, we can very easily change Events in XAML
this:
Panels
Introduction to WPF Panels
The Canvas
The WrapPanel
The StackPanel
The DockPanel
The Grid
The Grid - Rows & Columns
The Grid - Units
The Grid - Spanning
The Grid - GridSplitter
Using the Grid: A contact
The TabStripPlacement can be set to Top, Bottom, Left and Right. However, form
if we set it to Left or Right, we get a result like this:
Data binding
Introduction
Hello, bound world!
Using the DataContext
The UpdateSourceTrigger
property
Responding to changes
Value conversion with
IValueConverter
The StringFormat property
Debugging data bindings
I personally would expect that the tabs to be rotated when placed on one of
the sides, so that the tab text becomes vertical instead of horizontal, but the
WPF TabControl doesn't do this. Fortunately, we can accomplish this Commands
behavior with a small hack:
Introduction
Using commands
<Window
Implementing custom
x:Class="WpfTutorialSamples.Misc_controls.TabStripPlacementS
commands
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
Common interface
controls
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" The Menu control
Title="TabStripPlacementSample" Height="200" The ContextMenu
Width="250" UseLayoutRounding="True"> The ToolBar control
<Grid> The StatusBar control
<TabControl TabStripPlacement="Left"> The Ribbon Control
<TabControl.Resources>
<Style TargetType="{x:Type TabItem}">
<Setter Property="HeaderTemplate"> Rich Text controls
<Setter.Value> Introduction
<DataTemplate> The
<ContentPresenter FlowDocumentScrollViewer
Content="{TemplateBinding Content}"> control
The
<ContentPresenter.LayoutTransform> FlowDocumentPageViewer
<RotateTransform control
Angle="270" /> The FlowDocumentReader
control
</ContentPresenter.LayoutTransform> Creating a FlowDocument
</ContentPresenter> from Code-behind
</DataTemplate> Advanced FlowDocument
</Setter.Value> content
</Setter> The RichTextBox control
<Setter Property="Padding" Value="3"
/>
</Style>
Misc. controls
</TabControl.Resources>
The Border control
<TabItem Header="General">
The Slider control
<Label Content="Content goes here..." />
The ProgressBar control
</TabItem>
The WebBrowser control
<TabItem Header="Security" />
The WindowsFormsHost
<TabItem Header="Details" />
control
</TabControl>
</Grid>
</Window>
The TabControl
Using the TabControl
Tab positions
Styling the TabItems
List controls
The ItemsControl
The ListBox control
The ComboBox control
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
WPF TabControl: Styling the TabItems
Download this entire
tutorial as PDF right
now!
In one of the previous articles, we discovered how easy it was to customize About WPF
the tab headers of the WPF TabControl, for instance to add an image or color
What is WPF?
the text. However, if you wish to go beyond that and directly influence how
WPF vs. WinForms
the tab looks, including shape and borders, you need to override the control
template of the TabItem element, and while this is not as straight forward as
most other areas of WPF, it's still manageable.
Getting started
So, if you would like to get full control of how the tabs of your TabControl Visual Studio Express
looks, check out the next example: Hello, WPF!
<Window
x:Class="WpfTutorialSamples.Misc_controls.StyledTabItemsSamp XAML
What is XAML?
Basic XAML
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
Events in XAML
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
A WPF application
Title="StyledTabItemsSample" Height="150"
Width="250"> Introduction
<Grid> The Window
<TabControl Margin="10" BorderThickness="0" Working with App.xaml
Background="LightGray"> Command-line parameters
<TabControl.Resources> Resources
<Style TargetType="TabItem"> Handling exceptions
<Setter Property="Template">
<Setter.Value>
<ControlTemplate Basic controls
TargetType="TabItem"> The TextBlock control
<Grid Name="Panel"> The TextBlock control - Inline
<ContentPresenter formatting
x:Name="ContentSite" The Label control
The TextBox control
VerticalAlignment="Center" The CheckBox control
ContentSource="Header"
Margin="10,2"/>
Panels
</Grid>
<ControlTemplate.Triggers> Introduction to WPF Panels
<Trigger The Canvas
Property="IsSelected" Value="True"> The WrapPanel
<Setter The StackPanel
TargetName="Panel" Property="Background" The DockPanel
Value="LightSkyBlue" /> The Grid
</Trigger> The Grid - Rows & Columns
<Trigger The Grid - Units
Property="IsSelected" Value="False"> The Grid - Spanning
<Setter The Grid - GridSplitter
TargetName="Panel" Property="Background" Value="White" /> Using the Grid: A contact
</Trigger> form
</ControlTemplate.Triggers>
</ControlTemplate> Data binding
</Setter.Value> Introduction
</Setter> Hello, bound world!
</Style> Using the DataContext
</TabControl.Resources> The UpdateSourceTrigger
<TabItem Header="General"> property
<Label Content="Content goes here..." /> Responding to changes
</TabItem> Value conversion with
<TabItem Header="Security" /> IValueConverter
<TabItem Header="Details" /> The StringFormat property
</TabControl> Debugging data bindings
</Grid>
</Window>
Commands
Introduction
Using commands
Implementing custom
commands
Common interface
controls
The Menu control
As you can see, this makes the TabControl looks a bit Windows 8'ish, with no The ContextMenu
borders and a less subtle color to mark the selected tab and no background The ToolBar control
for
the unselected tabs. All of this is accomplished by changing the The StatusBar control
ControlTemplate, using a Style. By adding a ContentPresenter control, we The Ribbon Control
specify where the content of the TabItem should be placed. We also have a
couple of triggers, which controls the background color of the tabs based on
the IsSelected property. Rich Text controls
In case you want a less subtle look, it's as easy as changing the template. Introduction
For instance, you might want a border, but with round corners and a gradient The
background - no problem! Check out this next example, where we FlowDocumentScrollViewer
accomplish just that: control
The
FlowDocumentPageViewer
<Window
control
x:Class="WpfTutorialSamples.Misc_controls.StyledTabItemsWith
The FlowDocumentReader
control
Creating a FlowDocument
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
from Code-behind
Advanced FlowDocument
content
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
The RichTextBox control
Title="StyledTabItemsWithBorderSample"
Height="150" Width="250">
<Grid>
<TabControl Margin="10" BorderBrush="Gainsboro">
Misc. controls
<TabControl.Resources> The Border control
<Style TargetType="TabItem"> The Slider control
<Setter Property="Template"> The ProgressBar control
<Setter.Value> The WebBrowser control
<ControlTemplate The WindowsFormsHost
TargetType="TabItem"> control
<Border Name="Border"
BorderThickness="1,1,1,0" BorderBrush="Gainsboro"
CornerRadius="4,4,0,0" Margin="2,0"> The TabControl
<ContentPresenter
Using the TabControl
x:Name="ContentSite"
Tab positions
Styling the TabItems
VerticalAlignment="Center"
HorizontalAlignment="Center"
List controls
ContentSource="Header" The ItemsControl
Margin="10,2"/> The ListBox control
</Border> The ComboBox control
<ControlTemplate.Triggers>
<Trigger
Property="IsSelected" Value="True"> The ListView control
<Setter Introduction
TargetName="Border" Property="Background" A simple ListView
Value="LightSkyBlue" /> ListView, data binding and
</Trigger> ItemTemplate
<Trigger ListView with a GridView
Property="IsSelected" Value="False"> How-to: Left aligned column
<Setter names
TargetName="Border" Property="Background" ListView grouping
Value="GhostWhite" /> ListView sorting
</Trigger> How-to: ListView with
column sorting
Styles
Introduction
Using styles
Triggers
Multi triggers
As you can see, I pretty much just added a Border control around the
Trigger animations
ContentPresenter to achieve this changed look. Hopefully this should
demonstrate just
how easy it is to get custom styled tabs and how many
possibilities there are in this technique.
Misc.
Previous Next The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
The ItemsControl
Download this entire
tutorial as PDF right
now!
WPF has a wide range of controls for displaying a list of data. They come in About WPF
several shapes and forms and vary in how complex they are and how much
What is WPF?
work
they perform for you. The simplest variant is the ItemsControl, which is
WPF vs. WinForms
pretty much just a markup-based loop - you need to apply all the styling and
templating, but in many cases, that's just what you need.
A simple ItemsControl example Getting started
Visual Studio Express
Let's kick off with a very simple example, where we hand-feed the
Hello, WPF!
ItemsControl with a set of items. This should show you just how simple the
ItemsControl
is:
XAML
<Window
What is XAML?
x:Class="WpfTutorialSamples.ItemsControl.ItemsControlSample"
Basic XAML
Events in XAML
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
A WPF application
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Introduction
xmlns:system="clr- The Window
namespace:System;assembly=mscorlib" Working with App.xaml
Title="ItemsControlSample" Height="150" Command-line parameters
Width="200"> Resources
<Grid Margin="10"> Handling exceptions
<ItemsControl>
<system:String>ItemsControl Item
#1</system:String> Basic controls
<system:String>ItemsControl Item
The TextBlock control
#2</system:String>
The TextBlock control - Inline
<system:String>ItemsControl Item
formatting
#3</system:String>
The Label control
<system:String>ItemsControl Item
The TextBox control
#4</system:String>
The CheckBox control
<system:String>ItemsControl Item
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
Common interface
controls
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ItemsControlDataBindingSample" Height="150" The Menu control
Width="300"> The ContextMenu
<Grid Margin="10"> The ToolBar control
<ItemsControl Name="icTodoList"> The StatusBar control
<ItemsControl.ItemTemplate> The Ribbon Control
<DataTemplate>
<Grid
Margin="0,0,0,5"> Rich Text controls
Introduction
<Grid.ColumnDefinitions> The
FlowDocumentScrollViewer
<ColumnDefinition Width="*" /> control
The
<ColumnDefinition Width="100" /> FlowDocumentPageViewer
control
</Grid.ColumnDefinitions> The FlowDocumentReader
<TextBlock control
Text="{Binding Title}" /> Creating a FlowDocument
from Code-behind
<ProgressBar Grid.Column="1" Minimum="0" Maximum="100" Advanced FlowDocument
Value="{Binding Completion}" /> content
</Grid> The RichTextBox control
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl> Misc. controls
</Grid>
The Border control
</Window>
The Slider control
The ProgressBar control
The WebBrowser control
using System; The WindowsFormsHost
using System.Windows; control
using System.Collections.Generic;
The most important part of this example is the template that we specify inside
of the ItemsControl, using a DataTemplate tag inside of the The DataGrid control
ItemsControl.ItemTemplate. We add a Grid panel, to get two columns: In the Introduction
first we have a TextBlock, which will show the title of the TODO item, and in Custom columns
the second column we have a ProgressBar control, which value we bind to Details row
the Completion property.
The template now represents a TodoItem, which we declare in the Code-
Styles
behind file, where we also instantiate a number of them and add them to a
Introduction
list. In the
end, this list is assigned to the ItemsSource property of our
Using styles
ItemsControl, which then does the rest of the job for us. Each item in the
list
Triggers
is displayed by using our template, as you can see from the resulting
Multi triggers
screenshot.
Trigger animations
The ItemsPanelTemplate property
In the above examples, all items are rendered from top to bottom, with each Misc.
item taking up the full row. This happens because the ItemsControl throw all
The DispatcherTimer
of
our items into a vertically aligned StackPanel by default. It's very easy to
change though, since the ItemsControl allows you to change which panel
type is
used to hold all the items. Here's an example:
Audio & Video
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-
namespace:System;assembly=mscorlib"
Title="ItemsControlPanelSample" Height="150"
Width="250">
<Grid Margin="10">
<ItemsControl>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="
{Binding}" Margin="0,0,5,5" />
</DataTemplate>
</ItemsControl.ItemTemplate>
<system:String>Item
#1</system:String>
<system:String>Item
#2</system:String>
<system:String>Item
#3</system:String>
<system:String>Item
#4</system:String>
<system:String>Item
#5</system:String>
</ItemsControl>
</Grid>
</Window>
We specify that the ItemsControl should use a WrapPanel as its template by
declaring one in the ItemsPanelTemplate property and just for
fun, we throw
in an ItemTemplate that causes the strings to be rendered as buttons. You
can use any of the WPF panels, but some are more useful than
others.
Another good example is the UniformGrid panel, where we can define a
number of columns and then have our items neatly shown in equally-wide
columns:
<Window
x:Class="WpfTutorialSamples.ItemsControl.ItemsControlPanelSa
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-
namespace:System;assembly=mscorlib"
Title="ItemsControlPanelSample" Height="150"
Width="250">
<Grid Margin="10">
<ItemsControl>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid
Columns="2" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="
{Binding}" Margin="0,0,5,5" />
</DataTemplate>
</ItemsControl.ItemTemplate>
<system:String>Item
#1</system:String>
<system:String>Item
#2</system:String>
<system:String>Item
#3</system:String>
<system:String>Item
#4</system:String>
<system:String>Item
#5</system:String>
</ItemsControl>
</Grid>
</Window>
ItemsControl with scrollbars
Once you start using the ItemsControl, you might run into a very common
problem: By default, the ItemsControl doesn't have any scrollbars, which
means that
if the content doesn't fit, it's just clipped. This can be seen by
taking our first example from this article and resizing the window:
WPF makes this very easy to solve though. There are a number of possible
solutions, for instance you can alter the template used by the ItemsControl to
include a ScrollViewer control, but the easiest solution is to simply throw a
ScrollViewer around the ItemsControl. Here's an example:
<Window
x:Class="WpfTutorialSamples.ItemsControl.ItemsControlSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-
namespace:System;assembly=mscorlib"
Title="ItemsControlSample" Height="150"
Width="200">
<Grid Margin="10">
<ScrollViewer
VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Auto">
<ItemsControl>
<system:String>ItemsControl Item #1</system:String>
<system:String>ItemsControl Item #2</system:String>
<system:String>ItemsControl Item #3</system:String>
<system:String>ItemsControl Item #4</system:String>
<system:String>ItemsControl Item #5</system:String>
</ItemsControl>
</ScrollViewer>
</Grid>
</Window>
I set the two visibility options to Auto, to make them only visible when
needed. As you can see from the screenshot, you can now scroll through the
list of
items.
Summary
The ItemsControl is great when you want full control of how your data is
displayed, and when you don't need any of your content to be selectable. If
you
want the user to be able to select items from the list, then you're better
off with one of the other controls, e.g. the ListBox or the ListView. They will
be described in upcoming chapters.
Previous Next
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
The ListBox control
Download this entire
tutorial as PDF right
now!
In the last article, we had a look at the ItemsControl, which is probably the About WPF
simplest list in WPF. The ListBox control is the next control in line, which
What is WPF?
adds a bit more functionality. One of the main differences is the fact that the
WPF vs. WinForms
ListBox control actually deals with selections, allowing the end-user to
select
one or several items from the list and automatically giving visual feedback for
it.
Getting started
Here's an example of a very simple ListBox control: Visual Studio Express
Hello, WPF!
<Window
x:Class="WpfTutorialSamples.ListBox_control.ListBoxSample"
XAML
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
What is XAML?
Basic XAML
Events in XAML
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ListBoxSample" Height="120" Width="200">
<Grid Margin="10">
A WPF application
<ListBox>
<ListBoxItem>ListBox Item Introduction
#1</ListBoxItem> The Window
<ListBoxItem>ListBox Item Working with App.xaml
#2</ListBoxItem> Command-line parameters
<ListBoxItem>ListBox Item Resources
#3</ListBoxItem> Handling exceptions
</ListBox>
</Grid>
</Window> Basic controls
The TextBlock control
The TextBlock control - Inline
formatting
The Label control
The TextBox control
The CheckBox control
This is as simple as it gets: We declare a ListBox control, and inside of it, we
declare three ListBoxItem's, each with its own text. However, since the Panels
ListBoxItem is actually a ContentControl, we can define custom content for it:
Introduction to WPF Panels
The Canvas
<Window The WrapPanel
x:Class="WpfTutorialSamples.ListBox_control.ListBoxSample" The StackPanel
The DockPanel
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta The Grid
The Grid - Rows & Columns
The Grid - Units
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" The Grid - Spanning
Title="ListBoxSample" Height="120" Width="200"> The Grid - GridSplitter
<Grid Margin="10"> Using the Grid: A contact
<ListBox> form
<ListBoxItem>
<StackPanel
Orientation="Horizontal">
Data binding
<Image
Introduction
Source="/WpfTutorialSamples;component/Images/bullet_blue.png
Hello, bound world!
/>
Using the DataContext
<TextBlock>ListBox
The UpdateSourceTrigger
Item #1</TextBlock>
property
</StackPanel>
Responding to changes
</ListBoxItem>
Value conversion with
<ListBoxItem>
IValueConverter
<StackPanel
The StringFormat property
Orientation="Horizontal">
Debugging data bindings
<Image
Source="/WpfTutorialSamples;component/Images/bullet_green.pn
/>
<TextBlock>ListBox Commands
Item #2</TextBlock> Introduction
</StackPanel> Using commands
</ListBoxItem> Implementing custom
<ListBoxItem> commands
<StackPanel
Orientation="Horizontal">
<Image Common interface
Source="/WpfTutorialSamples;component/Images/bullet_red.png" controls
/>
The Menu control
<TextBlock>ListBox
The ContextMenu
Item #3</TextBlock>
The ToolBar control
</StackPanel>
The StatusBar control
</ListBoxItem>
I have re-used the TODO based example from the ItemsControl article, The TabControl
where we build a cool TODO list using a simple Code-behind class and, in Using the TabControl
this case, a
ListBox control for the visual representation. Here's the example: Tab positions
Styling the TabItems
<Window
x:Class="WpfTutorialSamples.ListBox_control.ListBoxDataBindi
List controls
The ItemsControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
The ListBox control
The ComboBox control
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ListBoxDataBindingSample" Height="150"
The ListView control
Width="300">
<Grid Margin="10"> Introduction
<ListBox Name="lbTodoList" A simple ListView
HorizontalContentAlignment="Stretch"> ListView, data binding and
<ListBox.ItemTemplate> ItemTemplate
<DataTemplate> ListView with a GridView
<Grid How-to: Left aligned column
Margin="0,2"> names
ListView grouping
<Grid.ColumnDefinitions> ListView sorting
How-to: ListView with
<ColumnDefinition Width="*" /> column sorting
ListView filtering
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions> The TreeView control
<TextBlock Introduction
Text="{Binding Title}" /> A simple TreeView
TreeView, data binding and
<ProgressBar Grid.Column="1" Minimum="0" Maximum="100" multiple templates
Value="{Binding Completion}" /> Handling
</Grid> Selection/Expansion state
</DataTemplate> Lazy loading TreeView items
</ListBox.ItemTemplate>
</ListBox>
</Grid>
The DataGrid control
</Window>
Introduction
Custom columns
Details row
using System;
using System.Windows;
using System.Collections.Generic; Styles
Introduction
namespace WpfTutorialSamples.ListBox_control
Using styles
{
Triggers
public partial class ListBoxDataBindingSample :
Multi triggers
Window
Trigger animations
{
public ListBoxDataBindingSample()
{
InitializeComponent();
Misc.
List<TodoItem> items = new The DispatcherTimer
List<TodoItem>();
items.Add(new TodoItem() { Title =
"Complete this WPF tutorial", Completion = 45 }); Audio & Video
items.Add(new TodoItem() { Title =
Playing audio
"Learn C#", Completion = 80 });
Playing video
items.Add(new TodoItem() { Title =
How-to: Complete media
"Wash the car", Completion = 0 });
player
Speech synthesis
lbTodoList.ItemsSource = items;
Speech recognition
}
}
}
}
All the magic happens in the ItemTemplate that we have defined for the
ListBox. In there, we specify that each ListBox item should consist of a Grid,
divided into two columns, with a TextBlock showing the title in the first and a
ProgressBar showing the completion status in the second column. To get the
values out, we use some very simple data binding, which is all explained in
the data binding part of this tutorial.
In the Code-behind file, we have declared a very simple TodoItem class to
hold each of our TODO items. In the constructor of the window, we initialize a
list, add three TODO items to it and then assign it to the ItemsSource of the
ListBox. The combination of the ItemsSource and the ItemTemplate we
specified
in the XAML part, this is all WPF need to render all of the items as a
TODO list.
Please notice the HorizontalContentAlignment property that I set to
Stretch on the ListBox. The default content alignment
for a ListBox item is
Left, which means that each item only takes up as much horizontal space as
it needs. The result? Well, not quite
what we want:
By using the Stretch alignment, each item is stretched to take up the full
amount of available space, as you can see from the previous screenshot.
Working with ListBox selection
As mentioned, a key difference between the ItemsControl and the ListBox is
that the ListBox handles and displays user selection for you. Therefore, a lot
of ListBox question revolves around somehow working with the selection. To
help with some of these questions, I have created a bigger example, showing
you
some selection related tricks:
<Window
x:Class="WpfTutorialSamples.ListBox_control.ListBoxSelection
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ListBoxSelectionSample" Height="250"
Width="450">
<DockPanel Margin="10">
<StackPanel DockPanel.Dock="Right"
Margin="10,0">
<StackPanel.Resources>
<Style
TargetType="Button">
<Setter
Property="Margin" Value="0,0,0,5" />
</Style>
</StackPanel.Resources>
<TextBlock FontWeight="Bold"
Margin="0,0,0,10">ListBox selection</TextBlock>
<Button Name="btnShowSelectedItem"
Click="btnShowSelectedItem_Click">Show selected</Button>
<Button Name="btnSelectLast"
Click="btnSelectLast_Click">Select last</Button>
<Button Name="btnSelectNext"
Click="btnSelectNext_Click">Select next</Button>
<Button Name="btnSelectCSharp"
Click="btnSelectCSharp_Click">Select C#</Button>
<Button Name="btnSelectAll"
Click="btnSelectAll_Click">Select all</Button>
</StackPanel>
<ListBox Name="lbTodoList"
HorizontalContentAlignment="Stretch"
SelectionMode="Extended"
SelectionChanged="lbTodoList_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid
Margin="0,2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<TextBlock
Text="{Binding Title}" />
using System;
using System.Windows;
using System.Collections.Generic;
namespace WpfTutorialSamples.ListBox_control
{
public partial class ListBoxSelectionSample :
Window
{
public ListBoxSelectionSample()
{
InitializeComponent();
List<TodoItem> items = new
List<TodoItem>();
items.Add(new TodoItem() { Title =
"Complete this WPF tutorial", Completion = 45 });
items.Add(new TodoItem() { Title =
"Learn C#", Completion = 80 });
items.Add(new TodoItem() { Title =
"Wash the car", Completion = 0 });
lbTodoList.ItemsSource = items;
}
private void
lbTodoList_SelectionChanged(object sender,
System.Windows.Controls.SelectionChangedEventArgs e)
{
if(lbTodoList.SelectedItem !=
null)
this.Title =
(lbTodoList.SelectedItem as TodoItem).Title;
}
private void
btnShowSelectedItem_Click(object sender, RoutedEventArgs
e)
{
foreach(object o in
lbTodoList.SelectedItems)
MessageBox.Show((o as
TodoItem).Title);
}
As you can see, I have defined a range of buttons to the right of the ListBox,
to either get or manipulate the selection. I've also changed the
SelectionMode to Extended, to allow for the selection of multiple items. This
can be done either programmatically, as I
do in the example, or by the end-
user, by holding down [Ctrl] or [Shift] while clicking on the items.
For each of the buttons, I have defined a click handler in the Code-behind.
Each action should be pretty self-explanatory and the C# code used is fairly
simple, but if you're still in doubt, try running the example on your own
machine and test out the various possibilities in the example.
Summary
The ListBox control is much like the ItemsControl and several of the same
techniques can be used. The ListBox does offer a bit more functionality when
compared to the ItemsControl, especially the selection handling. For even
more functionality, like column headers, you should have a look at the
ListView
control, which is given a very thorough description later on in this
tutorial with several articles explaining all the functionality.
Previous Next
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
The ComboBox control
Download this entire
tutorial as PDF right
now!
The ComboBox control is in many ways like the ListBox control, but takes up About WPF
a lot less space, because the list of items is hidden when not needed. The
What is WPF?
ComboBox control is used many places in Windows, but to make sure that
WPF vs. WinForms
everyone knows how it looks and works, we'll jump straight into a simple
example:
Getting started
<Window
x:Class="WpfTutorialSamples.ComboBox_control.ComboBoxSample" Visual Studio Express
Hello, WPF!
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
XAML
What is XAML?
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Basic XAML
Title="ComboBoxSample" Height="150" Width="200"> Events in XAML
<StackPanel Margin="10">
<ComboBox>
<ComboBoxItem>ComboBox Item #1</ComboBoxItem>
A WPF application
<ComboBoxItem IsSelected="True">ComboBox Item
Introduction
#2</ComboBoxItem>
The Window
<ComboBoxItem>ComboBox Item #3</ComboBoxItem>
Working with App.xaml
</ComboBox>
Command-line parameters
</StackPanel>
Resources
</Window>
Handling exceptions
Basic controls
The TextBlock control
The TextBlock control - Inline
formatting
The Label control
The TextBox control
The CheckBox control
In the screenshot, I have activated the control by clicking it, causing the list of The RadioButton control
items to be displayed. As you can see from the code, the ComboBox, in
its The PasswordBox control
simple form, is very easy to use. All I've done here is manually add some
items, making one of them the default selected item by setting the IsSelected
property on it. Panels
Custom content Introduction to WPF Panels
The Canvas
In the first example we only showed text in the items, which is pretty common The WrapPanel
for the ComboBox control, but since the ComboBoxItem is a ContentControl, The StackPanel
we
can actually use pretty much anything as content. Let's try making a The DockPanel
slightly more sophisticated list of items: The Grid
The Grid - Rows & Columns
<Window The Grid - Units
x:Class="WpfTutorialSamples.ComboBox_control.ComboBoxCustomC The Grid - Spanning
The Grid - GridSplitter
Using the Grid: A contact
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta form
</ComboBoxItem>
Introduction
</ComboBox>
The
</StackPanel>
FlowDocumentScrollViewer
</Window>
control
The
FlowDocumentPageViewer
control
The FlowDocumentReader
control
Creating a FlowDocument
from Code-behind
Advanced FlowDocument
content
The RichTextBox control
For each of the ComboBoxItem's we now add a StackPanel, in which we add
an Image and a TextBlock. This gives us full control of the content as well as
the
text rendering, as you can see from the screenshot, where both text color Misc. controls
and image indicates a color value. The Border control
The Slider control
Data binding the ComboBox The ProgressBar control
The WebBrowser control
As you can see from the first examples, manually defining the items of a
The WindowsFormsHost
ComboBox control is easy using XAML, but you will likely soon run into a
control
situation
where you need the items to come from some kind of data source,
like a database or just an in-memory list. Using WPF data binding and a
custom template, we
can easily render a list of colors, including a preview of
The TabControl
the color:
Using the TabControl
Tab positions
<Window
Styling the TabItems
x:Class="WpfTutorialSamples.ComboBox_control.ComboBoxDataBin
</ComboBox>
ListView filtering
</StackPanel>
</Window>
Misc.
The DispatcherTimer
Each item, as defined by the ItemTemplate, consists of a StackPanel with a
Rectangle and a TextBlock, each bound to the color value. This gives us a
complete list of colors, with minimal effort - and it looks pretty good too, right?
IsEditable
In the first examples, the user was only able to select from our list of items,
but one of the cool things about the ComboBox is that it supports the
possibility of letting the user both select from a list of items or enter their own
value. This is extremely useful in situations where you want to help
the user
by giving them a pre-defined set of options, while still giving them the option
to manually enter the desired value. This is all controlled by the IsEditable
property, which changes the behavior and look of the ComboBox quite a bit:
<Window
x:Class="WpfTutorialSamples.ComboBox_control.ComboBoxEditabl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ComboBoxEditableSample" Height="150"
Width="200">
<StackPanel Margin="10">
<ComboBox IsEditable="True">
<ComboBoxItem>ComboBox Item #1</ComboBoxItem>
<ComboBoxItem>ComboBox Item #2</ComboBoxItem>
<ComboBoxItem>ComboBox Item #3</ComboBoxItem>
</ComboBox>
</StackPanel>
</Window>
As you can see, I can enter a completely different value or pick one from the
list. If picked from the list, it simply overwrites the text of the ComboBox.
As a lovely little bonus, the ComboBox will automatically try to help the user
select an existing value when the user starts typing, as you can see from
the
next screenshot, where I just started typing "Co":
By default, the matching is not case-sensitive but you can make it so by
setting the IsTextSearchCaseSensitive to True. If you don't want
this auto
complete behavior at all, you can disable it by setting the
IsTextSearchEnabled to False.
Working with ComboBox selection
A key part of using the ComboBox control is to be able to read the user
selection, and even control it with code. In the next example, I've re-used the
data bound ComboBox example, but added some buttons for controlling the
selection. I've also used the SelectionChanged event to capture
when the
selected item is changed, either by code or by the user, and act on it.
Here's the sample:
<Window
x:Class="WpfTutorialSamples.ComboBox_control.ComboBoxSelecti
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ComboBoxSelectionSample" Height="125"
Width="250">
<StackPanel Margin="10">
<ComboBox Name="cmbColors"
SelectionChanged="cmbColors_SelectionChanged">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Rectangle Fill="{Binding Name}"
Width="16" Height="16" Margin="0,2,5,2" />
<TextBlock Text="{Binding Name}"
/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<WrapPanel Margin="15"
HorizontalAlignment="Center">
<Button Name="btnPrevious"
Click="btnPrevious_Click" Width="55">Previous</Button>
<Button Name="btnNext" Click="btnNext_Click"
Margin="5,0" Width="55">Next</Button>
<Button Name="btnBlue" Click="btnBlue_Click"
Width="55">Blue</Button>
</WrapPanel>
</StackPanel>
</Window>
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Windows;
using System.Windows.Media;
namespace WpfTutorialSamples.ComboBox_control
{
public partial class ComboBoxSelectionSample :
Window
{
public ComboBoxSelectionSample()
{
InitializeComponent();
cmbColors.ItemsSource =
typeof(Colors).GetProperties();
}
private void
cmbColors_SelectionChanged(object sender,
System.Windows.Controls.SelectionChangedEventArgs e)
{
Color selectedColor = (Color)
(cmbColors.SelectedItem as PropertyInfo).GetValue(null,
null);
this.Background = new
SolidColorBrush(selectedColor);
}
}
The interesting part of this example is the three event handlers for our three
buttons, as well as the SelectionChanged event handler. In
the first two, we
select the previous or the next item by reading the SelectedIndex property
and then subtracting or adding one to it.
Pretty simple and easy to work with.
In the third event handler, we use the SelectedItem to select a specific item
based on the value. I do a bit of extra work here (using .NET reflection),
because the ComboBox is bound to a list of properties, each being a color,
instead of a simple list of colors, but basically it's all about giving the
value
contained by one of the items to the SelectedItem property.
In the fourth and last event handler, I respond to the selected item being
changed. When that happens, I read the selected color (once again using
Reflection, as described above) and then use the selected color to create a
new background brush for the Window. The effect can be seen on the
screenshot.
If you're working with an editable ComboBox (IsEditable property set to true),
you can read the Text property to know the value the user
has entered or
selected.
Previous Next
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
Introduction to the ListView control
Download this entire
tutorial as PDF right
now!
The ListView control is very commonly used in Windows applications, to About WPF
represent lists of data. A great example of this is the file lists in Windows
What is WPF?
Explorer, where each file can be shown by its name and, if desired, with
WPF vs. WinForms
columns containing information about the size, last modification date and so
on.
Panels
Introduction to WPF Panels
The Canvas
The WrapPanel
The StackPanel
The DockPanel
The Grid
The Grid - Rows & Columns
The Grid - Units
The Grid - Spanning
The Grid - GridSplitter
Using the Grid: A contact
form
Data binding
Introduction
Hello, bound world!
Using the DataContext
The UpdateSourceTrigger
property
Responding to changes
Value conversion with
IValueConverter
The StringFormat property
Debugging data bindings
Commands
Introduction
Using commands
Implementing custom
commands
Common interface
controls
The Menu control
The ContextMenu
The ToolBar control
The StatusBar control
The Ribbon Control
Introduction
The
FlowDocumentScrollViewer
control
The
FlowDocumentPageViewer
control
The FlowDocumentReader
control
Creating a FlowDocument
from Code-behind
Advanced FlowDocument
content
The RichTextBox control
Misc. controls
The Border control
The Slider control
The ProgressBar control
The WebBrowser control
The WindowsFormsHost
control
The TabControl
Using the TabControl
Tab positions
Styling the TabItems
List controls
The ItemsControl
The ListBox control
The ComboBox control
ListView filtering
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
A simple ListView example
Download this entire
tutorial as PDF right
now!
The WPF ListView control is very bare minimum in its most simple form. In About WPF
fact, it will look a whole lot like the WPF ListBox, until you start adding
What is WPF?
specialized views to it. That's not so strange, since a ListView inherits directly
WPF vs. WinForms
from the ListBox control. So, a default ListView is actually just a ListBox, with
a different selection mode (more on that later).
Let's try creating a ListView in its most simple form: Getting started
Visual Studio Express
<Window Hello, WPF!
x:Class="WpfTutorialSamples.ListView_control.ListViewBasicSa
XAML
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
What is XAML?
Basic XAML
Events in XAML
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ListViewBasicSample" Height="200"
Width="200">
A WPF application
<Grid>
<ListView Margin="10"> Introduction
<ListViewItem>A The Window
ListView</ListViewItem> Working with App.xaml
<ListViewItem Command-line parameters
IsSelected="True">with several</ListViewItem> Resources
<ListViewItem>items</ListViewItem> Handling exceptions
</ListView>
</Grid>
</Window> Basic controls
The TextBlock control
The TextBlock control - Inline
formatting
The Label control
The TextBox control
The CheckBox control
Panels
Introduction to WPF Panels
The Canvas
This is pretty much as simple as it gets, using manually specified The WrapPanel
ListViewItem to fill the list and with nothing but a text label representing each The StackPanel
item - a bare minimum WPF ListView control. The DockPanel
The Grid
ListViewItem with an image The Grid - Rows & Columns
The Grid - Units
Because of the look-less nature of WPF, specifying an image for a
The Grid - Spanning
ListViewItem isn't just about assigning an image ID or key to a property.
The Grid - GridSplitter
Instead, you take full control of it and specify the controls needed to render
Using the Grid: A contact
both image and text in the ListViewItem. Here's an example:
form
<Window
x:Class="WpfTutorialSamples.ListView_control.ListViewBasicSa
Data binding
Introduction
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta Hello, bound world!
Using the DataContext
The UpdateSourceTrigger
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" property
Title="ListViewBasicSample" Height="200" Responding to changes
Width="200"> Value conversion with
<Grid> IValueConverter
<ListView Margin="10"> The StringFormat property
<ListViewItem> Debugging data bindings
<StackPanel
Orientation="Horizontal">
<Image Commands
Source="/WpfTutorialSamples;component/Images/bullet_green.pn Introduction
Margin="0,0,5,0" /> Using commands
Implementing custom
<TextBlock>Green</TextBlock> commands
</StackPanel>
</ListViewItem>
<ListViewItem>
Common interface
<StackPanel
controls
Orientation="Horizontal">
The Menu control
<Image
The ContextMenu
Source="/WpfTutorialSamples;component/Images/bullet_blue.png
The ToolBar control
Margin="0,0,5,0" />
The StatusBar control
Misc. controls
The Border control
The Slider control
The ProgressBar control
The WebBrowser control
What we do here is very simple. Because the ListViewItem derives from the The WindowsFormsHost
ContentControl class, we can specify a WPF control as its content. In this control
case, we use a StackPanel, which has an Image and a TextBlock as its child
controls.
The TabControl
Summary Using the TabControl
As you can see, building a ListView manually in XAML is very simple, but in Tab positions
most cases, your ListView data will come from some sort of data source, Styling the TabItems
which should be rendered in the ListView at runtime. We will look into doing
just that in the next chapter.
List controls
Previous Next The ItemsControl
The ListBox control
The ComboBox control
ListView grouping
ListView sorting
How-to: ListView with
column sorting
ListView filtering
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
ListView, data binding and
ItemTemplate Download this entire
tutorial as PDF right
now!
About WPF
In the previous article, we manually populated a ListView control through
What is WPF?
XAML code, but in WPF, it's all about data binding. The concept of data
WPF vs. WinForms
binding is explained in detail in another part of this tutorial, but generally
speaking it's about separating data from layout. So, let's try binding some
data to a ListView:
Getting started
<Window Visual Studio Express
x:Class="WpfTutorialSamples.ListView_control.ListViewDataBin Hello, WPF!
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta XAML
What is XAML?
Basic XAML
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Events in XAML
Title="ListViewDataBindingSample" Height="300"
Width="300">
<Grid>
A WPF application
<ListView Margin="10"
Introduction
Name="lvDataBinding"></ListView>
The Window
</Grid>
Working with App.xaml
</Window>
Command-line parameters
Resources
Handling exceptions
using System;
using System.Collections.Generic;
using System.Windows; Basic controls
The TextBlock control
namespace WpfTutorialSamples.ListView_control
The TextBlock control - Inline
{
formatting
public partial class ListViewDataBindingSample :
The Label control
Window
The TextBox control
{
The CheckBox control
public ListViewDataBindingSample()
Commands
Introduction
Using commands
Each user is represented by their type name in the ListView. This is to be Implementing custom
expected, because .NET doesn't have a clue about how you want your data commands
to be displayed, so it just calls the ToString() method on each object and
uses that to represent the item. We can use that to our advantage and
override the ToString() method, to get a more meaningful output. Try Common interface
replacing the User class with this version: controls
The Menu control
public class User The ContextMenu
{ The ToolBar control
public string Name { get; set; } The StatusBar control
The Ribbon Control
public int Age { get; set; }
{
Introduction
return this.Name + ", " + this.Age + "
The
years old";
FlowDocumentScrollViewer
}
control
}
The
FlowDocumentPageViewer
control
The FlowDocumentReader
control
Creating a FlowDocument
from Code-behind
Advanced FlowDocument
content
The RichTextBox control
This is a much more user friendly display and will do just fine in some cases,
but relying on a simple string is not that flexible. Perhaps you want a part of
the text to be bold or another color? Perhaps you want an image? Misc. controls
Fortunately, WPF makes all of this very simple using templates. The Border control
The Slider control
ListView with an ItemTemplate The ProgressBar control
The WebBrowser control
WPF is all about templating, so specifying a data template for the ListView is
The WindowsFormsHost
very easy. In this example, we'll do a bunch of custom formatting in each
control
item, just to show you how flexible this makes the WPF ListView.
We use a bunch of TextBlock controls to build each item, where we put part of
the text in bold. For the e-mail address, which we added to this example, we
underline it, give it a blue color and change the mouse cursor, to make it
behave like a hyperlink.
Summary
Using an ItemTemplate and data binding, we produced a pretty cool ListView
control. However, it still looks a lot like a ListBox. A very common usage
scenario for a ListView is to have columns, sometimes (e.g. in WinForms)
referred to as a details view. WPF comes with a built-in view class to handle
this, which we will talk about in the next chapter.
Previous Next
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
ListView with a GridView
Download this entire
tutorial as PDF right
now!
In the previous ListView articles, we have used the most basic version of the About WPF
WPF ListView, which is the one without a custom View specified. This results
What is WPF?
in a ListView that acts very much like the WPF ListBox, with some subtle
WPF vs. WinForms
differences. The real power lies in the views though and WPF comes with
one
specialized view built-in: The GridView.
By using the GridView, you can get several columns of data in your ListView, Getting started
much like you see it in Windows Explorer. Just to make sure that everyone Visual Studio Express
can
visualize it, we'll start off with a basic example: Hello, WPF!
<Window
x:Class="WpfTutorialSamples.ListView_control.ListViewGridVie XAML
What is XAML?
Basic XAML
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
Events in XAML
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
A WPF application
Title="ListViewGridViewSample" Height="200"
Width="400"> Introduction
<Grid> The Window
<ListView Margin="10" Name="lvUsers"> Working with App.xaml
<ListView.View> Command-line parameters
<GridView> Resources
<GridViewColumn Handling exceptions
Header="Name" Width="120" DisplayMemberBinding="{Binding
Name}" />
<GridViewColumn Basic controls
Header="Age" Width="50" DisplayMemberBinding="{Binding The TextBlock control
Age}" /> The TextBlock control - Inline
<GridViewColumn formatting
Header="Mail" Width="150" DisplayMemberBinding="{Binding The Label control
Mail}" /> The TextBox control
</GridView> The CheckBox control
</ListView.View>
Panels
Introduction to WPF Panels
using System; The Canvas
using System.Collections.Generic; The WrapPanel
using System.Windows; The StackPanel
The DockPanel
namespace WpfTutorialSamples.ListView_control The Grid
{ The Grid - Rows & Columns
public partial class ListViewGridViewSample : The Grid - Units
Window The Grid - Spanning
{ The Grid - GridSplitter
public ListViewGridViewSample() Using the Grid: A contact
{ form
InitializeComponent();
List<User> items = new List<User>
(); Data binding
items.Add(new User() { Name =
Introduction
"John Doe", Age = 42, Mail = "[email protected]" });
Hello, bound world!
items.Add(new User() { Name =
Using the DataContext
"Jane Doe", Age = 39, Mail = "[email protected]" });
The UpdateSourceTrigger
items.Add(new User() { Name =
property
"Sammy Doe", Age = 7, Mail = "[email protected]" });
Responding to changes
lvUsers.ItemsSource = items;
Value conversion with
}
IValueConverter
}
The StringFormat property
Debugging data bindings
public class User
{
public string Name { get; set; }
Commands
public int Age { get; set; } Introduction
Using commands
public string Mail { get; set; } Implementing custom
} commands
}
Common interface
controls
The Menu control
The ContextMenu
The ToolBar control
The StatusBar control
The Ribbon Control
Introduction
So, we use the same User class as previously, for test data, which we then The
bind to the ListView. This is all the same as we saw in previous chapters, but FlowDocumentScrollViewer
as you can see from the screenshot, the layout is very different. This is the control
power of data binding - the same data, but presented in a completely The
different way, just by changing the markup. FlowDocumentPageViewer
control
In the markup (XAML), we define a View for the ListView, using the The FlowDocumentReader
ListView.View property. We set it to a GridView, which is currently the only control
included
view type in WPF (you can easily create your own though!). The Creating a FlowDocument
GridView is what gives us the column-based view that you see on the from Code-behind
screenshot. Advanced FlowDocument
content
Inside of the GridView, we define three columns, one for each of the pieces
The RichTextBox control
of data that we wish to show. The Header property is used to
specify the text
that we would like to show for the column and then we use the
DisplayMemberBinding property to bind the value to a
property from our
User class. Misc. controls
The Border control
Templated cell content The Slider control
The ProgressBar control
Using the DisplayMemberBinding property is pretty much limited to
The WebBrowser control
outputting simple strings, with no custom formatting at all, but the WPF
The WindowsFormsHost
ListView is much more flexible than that. By specifying a CellTemplate, we
control
take full control of how the content is rendered within the
specific column cell.
The GridViewColumn will use the DisplayMemberBinding as its first priority, it
it's present. The second choice will be the CellTemplate property, which
we'll The TabControl
use for this example: Using the TabControl
Tab positions
<Window Styling the TabItems
x:Class="WpfTutorialSamples.ListView_control.ListViewGridVie
List controls
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta The ItemsControl
The ListBox control
The ComboBox control
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ListViewGridViewCellTemplateSample"
Height="200" Width="400">
The ListView control
<Grid>
Introduction
<ListView Margin="10" Name="lvUsers">
A simple ListView
<ListView.View>
ListView, data binding and
<GridView>
ItemTemplate
<GridViewColumn
ListView with a GridView
Header="Name" Width="120" DisplayMemberBinding="{Binding
How-to: Left aligned column
Name}" />
names
<GridViewColumn
ListView grouping
Header="Age" Width="50" DisplayMemberBinding="{Binding
ListView sorting
Age}" />
How-to: ListView with
<GridViewColumn
column sorting
Header="Mail" Width="150">
ListView filtering
<GridViewColumn.CellTemplate>
<DataTemplate> The TreeView control
Introduction
<TextBlock Text="{Binding Mail}" A simple TreeView
TextDecorations="Underline" Foreground="Blue" TreeView, data binding and
Cursor="Hand" /> multiple templates
Handling
</DataTemplate> Selection/Expansion state
Lazy loading TreeView items
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView> The DataGrid control
</ListView.View>
Introduction
</ListView>
Custom columns
</Grid>
Details row
</Window>
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Please notice: The Code-behind code for this example is the same as the one Audio & Video
used for the first example in this article. Playing audio
Playing video
We specify a custom CellTemplate for the last column, where we would like
How-to: Complete media
to do some special formatting for the e-mail addresses. For the
other
player
columns, where we just want basic text output, we stick with the
Speech synthesis
DisplayMemberBinding, simply because it requires way less markup.
Speech recognition
Previous Next
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
How-to: ListView with left aligned
column names Download this entire
tutorial as PDF right
now!
About WPF
In a normal ListView, the column names are left aligned, but for some
What is WPF?
reason, Microsoft decided to center the names by default in the WPF
WPF vs. WinForms
ListView. In many
cases this will make your application look out-of-style
compared to other Windows applications. This is how the ListView will look in
WPF by default:
Getting started
Visual Studio Express
Hello, WPF!
XAML
What is XAML?
Basic XAML
Events in XAML
A WPF application
Let's try changing that to left aligned column names. Unfortunately, there are
no direct properties on the GridViewColumn to control this, but fortunately Introduction
that doesn't mean that it can't be changed. The Window
Working with App.xaml
Using a Style, targeted at the GridViewColumHeader, which is the element Command-line parameters
used to show the header of a GridViewColumn, we can change the Resources
HorizontalAlignment
property. In this case it defaults to Center, but we can Handling exceptions
change it to Left, to accomplish what we want:
Commands
Introduction
Using commands
Implementing custom
commands
Common interface
The part that does all the work for us, is the Style defined in the Resources of controls
the ListView: The Menu control
The ContextMenu
<Style TargetType="{x:Type GridViewColumnHeader}"> The ToolBar control
<Setter The StatusBar control
Property="HorizontalContentAlignment" Value="Left" /> The Ribbon Control
</Style>
Introduction
By defining the Style within the control itself, it only applies to this particular
The
ListView. In many cases you might like to make it apply to all the ListViews
FlowDocumentScrollViewer
within the
same Window/Page or perhaps even globally across the
control
application. You can do this by either copying the style to the Window
The
resources or the Application
resources. Here's the same example, where we
FlowDocumentPageViewer
have applied the style to the entire Window instead of just the particular
control
ListView:
The FlowDocumentReader
control
<Window Creating a FlowDocument
x:Class="WpfTutorialSamples.ListView_control.ListViewGridVie from Code-behind
Advanced FlowDocument
content
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta The RichTextBox control
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Misc. controls
Title="ListViewGridViewSample" Height="200"
The Border control
Width="400">
The Slider control
<Window.Resources>
The ProgressBar control
<Style TargetType="{x:Type
The WebBrowser control
GridViewColumnHeader}">
The WindowsFormsHost
<Setter
control
Property="HorizontalContentAlignment" Value="Left" />
</Style>
</Window.Resources>
<Grid> The TabControl
<ListView Margin="10" Name="lvUsers"> Using the TabControl
<ListView.View> Tab positions
<GridView> Styling the TabItems
<GridViewColumn
Header="Name" Width="120" DisplayMemberBinding="{Binding
Name}" /> List controls
<GridViewColumn
The ItemsControl
Header="Age" Width="50" DisplayMemberBinding="{Binding
The ListBox control
Age}" />
The ComboBox control
<GridViewColumn
Header="Mail" Width="150" DisplayMemberBinding="{Binding
Mail}" />
</GridView>
The ListView control
</ListView.View> Introduction
</ListView> A simple ListView
</Grid> ListView, data binding and
</Window> ItemTemplate
ListView with a GridView
How-to: Left aligned column
names
In case you want another alignment, e.g. right alignment, you just change the ListView grouping
value of the style like this: ListView sorting
How-to: ListView with
column sorting
<Setter Property="HorizontalContentAlignment"
ListView filtering
Value="Right" />
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
ListView grouping
Download this entire
tutorial as PDF right
now!
As we already talked about earlier, the WPF ListView is very flexible. About WPF
Grouping is yet another thing that it supports out of the box, and it's both
What is WPF?
easy to
use and extremely customizable. Let's jump straight into the first
WPF vs. WinForms
example, then I'll explain it and afterwards we can use the standard WPF
tricks to
customize the appearance even further.
For this article, I've borrowed the sample code from a previous article and Getting started
then expanded on it to support grouping. It looks like this: Visual Studio Express
Hello, WPF!
<Window
x:Class="WpfTutorialSamples.ListView_control.ListViewGroupSa
XAML
What is XAML?
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
Basic XAML
Events in XAML
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ListViewGroupSample" Height="300"
A WPF application
Width="300">
<Grid Margin="10"> Introduction
<ListView Name="lvUsers"> The Window
<ListView.View> Working with App.xaml
<GridView> Command-line parameters
<GridViewColumn Header="Name" Resources
Width="120" DisplayMemberBinding="{Binding Name}" /> Handling exceptions
<GridViewColumn Header="Age"
Width="50" DisplayMemberBinding="{Binding Age}" />
</GridView> Basic controls
</ListView.View> The TextBlock control
The TextBlock control - Inline
<ListView.GroupStyle> formatting
<GroupStyle> The Label control
<GroupStyle.HeaderTemplate> The TextBox control
<DataTemplate> The CheckBox control
<TextBlock FontWeight="Bold"
CollectionView view =
Commands
(CollectionView)CollectionViewSource.GetDefaultView(lvUsers. Introduction
Using commands
PropertyGroupDescription Implementing custom
groupDescription = new PropertyGroupDescription("Sex"); commands
view.GroupDescriptions.Add(groupDescription);
} Common interface
} controls
The Menu control
public enum SexType { Male, Female };
The ContextMenu
The ToolBar control
public class User
The StatusBar control
{
The Ribbon Control
public string Name { get; set; }
Misc. controls
The Border control
The Slider control
The ProgressBar control
In XAML, I have added a GroupStyle to the ListView, in which I define a
The WebBrowser control
template for the header of each group. It consists of a TextBlock control,
The WindowsFormsHost
where
I've used a slightly larger and bold text to show that it's a group - as
control
we'll see later on, this can of course be customized a lot more. The TextBlock
Text property is bound to a Name property, but please be aware that this is
not the Name property on the data object (in this case the User class).
Instead, it is the name of the
group, as assigned by WPF, based on the The TabControl
property we use to divide the objects into groups. Using the TabControl
Tab positions
In Code-behind, we do the same as we did before: We create a list and add Styling the TabItems
some User objects to it and then we bind the list to the ListView - nothing
new
there, except for the new Sex property that I've added, which tells
whether the user is male or female.
List controls
After assigning an ItemsSource, we use this to get a CollectionView that the The ItemsControl
ListView creates for us. This specialized View instance contains a lot of The ListBox control
possibilities, including the ability to group the items. We use this by adding a The ComboBox control
so-called PropertyGroupDescription to the GroupDescriptions of the view.
This basically tells WPF to group by a specific property on the data objects,
in this case the Sex property. The ListView control
Introduction
Customizing the group header A simple ListView
The above example was great for showing the basics of ListView grouping, ListView, data binding and
but the look was a tad boring, so let's exploit the fact that WPF lets us define ItemTemplate
our own templates and spice things up. A common request is to be able to ListView with a GridView
collapse and expand the group, and while WPF doesn't provide this behavior How-to: Left aligned column
by
default, it's somewhat easy to implement yourself. We'll do it by names
completely re-templating the group container. ListView grouping
ListView sorting
It might look a bit cumbersome, but the principles used are somewhat simple How-to: ListView with
and you will see them in other situations when you customize the WPF column sorting
controls.
Here's the code: ListView filtering
<Window
x:Class="WpfTutorialSamples.ListView_control.ListViewCollaps The TreeView control
Introduction
A simple TreeView
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta TreeView, data binding and
multiple templates
Handling
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Selection/Expansion state
Title="ListViewCollapseExpandGroupSample" Lazy loading TreeView items
Height="300" Width="300">
<Grid Margin="10">
<ListView Name="lvUsers"> The DataGrid control
<ListView.View>
Introduction
<GridView>
Custom columns
<GridViewColumn Header="Name"
Details row
Width="120" DisplayMemberBinding="{Binding Name}" />
<GridViewColumn Header="Age"
Width="50" DisplayMemberBinding="{Binding Age}" />
</GridView> Styles
</ListView.View> Introduction
Using styles
<ListView.GroupStyle> Triggers
<GroupStyle> Multi triggers
<GroupStyle.ContainerStyle> Trigger animations
<Style TargetType="{x:Type
GroupItem}">
<Setter Property="Template"> Misc.
<Setter.Value>
The DispatcherTimer
<ControlTemplate>
<Expander
IsExpanded="True">
Audio & Video
<Expander.Header> Playing audio
Playing video
<StackPanel Orientation="Horizontal"> How-to: Complete media
player
<TextBlock Text="{Binding Name}" FontWeight="Bold" Speech synthesis
Foreground="Gray" FontSize="22" VerticalAlignment="Bottom" Speech recognition
/>
</StackPanel>
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListView.GroupStyle>
</ListView>
</Grid>
</Window>
The Code-behind is exactly the same as used in the first example - feel
free to scroll up and grab it.
Now our groups look a bit more exciting, and they even include an expander
button, that will toggle the visibility of the group items when you click it
(that's
why the single female user is not visible on the screenshot - I collapsed that
particular group). By using the ItemCount property that the group
exposes,
we can even show how many items each group currently consists of.
As you can see, it requires a bit more markup than we're used to, but this
example also goes a bit beyond what we usually do, so that seems fair.
When you
read through the code, you will quickly realize that many of the
lines are just common elements like style and template.
Summary
Adding grouping to the WPF ListView is very simple - all you need is a
GroupStyle with a HeaderTemplate, to tell the ListView how to render a
group, and a
few lines of Code-behind code to tell WPF which property to
group by. As you can see from the last example, the group is even very
customizable, allowing
you to create some really cool views, without too
much work.
Previous Next
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
ListView sorting
Download this entire
tutorial as PDF right
now!
In the last chapter we saw how we could group items in the WPF ListView by About WPF
accessing the View instance of the ListView and then adding a group
What is WPF?
description.
Applying sorting to a ListView is just as easy, and most of the
WPF vs. WinForms
process is exactly the same. Let's try a simple example where we sort the
user objects by
their age:
Getting started
<Window
x:Class="WpfTutorialSamples.ListView_control.ListViewSorting Visual Studio Express
Hello, WPF!
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
XAML
What is XAML?
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Basic XAML
Title="ListViewSortingSample" Height="200" Events in XAML
Width="300">
<Grid Margin="10">
<ListView Name="lvUsers">
A WPF application
<ListView.View>
Introduction
<GridView>
The Window
<GridViewColumn Header="Name"
Working with App.xaml
Width="120" DisplayMemberBinding="{Binding Name}" />
Command-line parameters
<GridViewColumn Header="Age"
Resources
Width="50" DisplayMemberBinding="{Binding Age}" />
Handling exceptions
</GridView>
</ListView.View>
</ListView>
</Grid> Basic controls
</Window> The TextBlock control
The TextBlock control - Inline
formatting
The Label control
using System;
The TextBox control
using System.Collections.Generic;
The CheckBox control
using System.ComponentModel;
namespace WpfTutorialSamples.ListView_control
Panels
{
public partial class ListViewSortingSample : Introduction to WPF Panels
Window The Canvas
{ The WrapPanel
public ListViewSortingSample() The StackPanel
{ The DockPanel
InitializeComponent(); The Grid
List<User> items = new List<User> The Grid - Rows & Columns
(); The Grid - Units
items.Add(new User() { Name = The Grid - Spanning
"John Doe", Age = 42 }); The Grid - GridSplitter
items.Add(new User() { Name = Using the Grid: A contact
"Jane Doe", Age = 39 }); form
items.Add(new User() { Name =
"Sammy Doe", Age = 13 });
items.Add(new User() { Name = Data binding
"Donna Doe", Age = 13 }); Introduction
lvUsers.ItemsSource = items; Hello, bound world!
Using the DataContext
CollectionView view = The UpdateSourceTrigger
(CollectionView)CollectionViewSource.GetDefaultView(lvUsers. property
Responding to changes
view.SortDescriptions.Add(new Value conversion with
SortDescription("Age", ListSortDirection.Ascending)); IValueConverter
} The StringFormat property
} Debugging data bindings
Common interface
controls
The Menu control
The ContextMenu
The ToolBar control
The StatusBar control
The Ribbon Control
Introduction
The XAML looks just like a previous example, where we simply have a The
couple of columns for displaying information about the user - nothing new FlowDocumentScrollViewer
here. control
The
In the Code-behind, we once again create a list of User objects, which we FlowDocumentPageViewer
then assign as the ItemsSource of the ListView. Once we've done that, we control
use the
ItemsSource property to get the CollectionView instance that the The FlowDocumentReader
ListView automatically creates for us and which we can use to manipulate control
how the ListView
shows our objects. Creating a FlowDocument
from Code-behind
With the view object in our hand, we add a new SortDescription to it,
Advanced FlowDocument
specifying that we want our list sorted by the Age property, in ascending
content
order. As
you can see from the screenshot, this works perfectly well - the list
The RichTextBox control
is sorted by age, instead of being in the same order as the items were added.
Multiple sort criteria
Misc. controls
As shown in the first example, sorting is very easy, but on the screenshot The Border control
you'll see that Sammy comes before Donna. They have the same age, so in The Slider control
this
case, WPF will just use the order in which they were added. Fortunately, The ProgressBar control
WPF lets us specify as many sort criteria as we want. In the example above, The WebBrowser control
try
changing the view-related code into something like this: The WindowsFormsHost
control
CollectionView view =
(CollectionView)CollectionViewSource.GetDefaultView(lvUsers.
The TabControl
view.SortDescriptions.Add(new SortDescription("Age",
Using the TabControl
ListSortDirection.Ascending));
Tab positions
view.SortDescriptions.Add(new SortDescription("Name",
Styling the TabItems
ListSortDirection.Ascending));
List controls
The ItemsControl
The ListBox control
The ComboBox control
A simple ListView
ListView, data binding and
ItemTemplate
Now the view will be sorted using age first, and when two identical values are
ListView with a GridView
found, the name will be used as a secondary sorting parameter.
How-to: Left aligned column
Summary names
ListView grouping
It's very easy to sort the contents of a ListView, as seen in the above ListView sorting
examples, but so far, all the sorting is decided by the programmer and not How-to: ListView with
the
end-user. In the next article I'll give you a how-to article showing you how column sorting
to let the user decide the sorting by clicking on the columns, as seen in ListView filtering
Windows.
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
How-to: ListView with column sorting
Download this entire
tutorial as PDF right
now!
In the last chapter we saw how we could easily sort a ListView from Code- About WPF
behind, and while this will suffice for some cases, it doesn't allow the end-user
What is WPF?
to decide on the sorting. Besides that, there was no indication on which
WPF vs. WinForms
column the ListView was sorted by. In Windows, and in many user interfaces
in
general, it's common to illustrate sort directions in a list by drawing a
triangle next to the column name currently used to sort by.
Getting started
In this how-to article, I'll give you a practical solution that gives us all of the Visual Studio Express
above, but please bear in mind that some of the code here goes a bit
beyond Hello, WPF!
what we have learned so far - that's why it has the "how-to" label.
This article builds upon the previous one, but I'll still explain each part as we
XAML
go along. Here's our goal - a ListView with column sorting, including
visual
indication of sort field and direction. The user simply clicks a column to sort What is XAML?
by and if the same column is clicked again, the sort direction is
reversed. Basic XAML
Here's how it looks: Events in XAML
A WPF application
Introduction
The Window
Working with App.xaml
Command-line parameters
Resources
Handling exceptions
Basic controls
The XAML The TextBlock control
The first thing we need is some XAML to define our user interface. It currently The TextBlock control - Inline
looks like this: formatting
The Label control
The TextBox control
<Window
The CheckBox control
x:Class="WpfTutorialSamples.ListView_control.ListViewColumnS
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
Panels
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Introduction to WPF Panels
Title="ListViewColumnSortingSample" Height="200" The Canvas
Width="350"> The WrapPanel
<Grid Margin="10"> The StackPanel
<ListView Name="lvUsers"> The DockPanel
<ListView.View> The Grid
<GridView> The Grid - Rows & Columns
<GridViewColumn Width="120" The Grid - Units
DisplayMemberBinding="{Binding Name}"> The Grid - Spanning
<GridViewColumn.Header> The Grid - GridSplitter
<GridViewColumnHeader Using the Grid: A contact
Tag="Name" form
Click="lvUsersColumnHeader_Click">Name</GridViewColumnHeader
The Tag property is used to hold the field name that will be used to sort by, if Introduction
this particular column is clicked. This is done in the The
lvUsersColumnHeader_Click event that each of the columns subscribes to. FlowDocumentScrollViewer
control
That was the key concepts of the XAML. Besides that, we bind to our Code- The
behind properties Name, Age and Sex, which we'll discuss now. FlowDocumentPageViewer
control
The Code-behind The FlowDocumentReader
control
In Code-behind, there are quite a few things happening. I use a total of three Creating a FlowDocument
classes, which you would normally divide up into individual files, but for from Code-behind
convenience, I have kept them in the same file, giving us a total of ~100 Advanced FlowDocument
lines. First the code and then I'll explain how it works: content
The RichTextBox control
using System;
using System.Collections.Generic;
using System.ComponentModel; Misc. controls
using System.Windows;
The Border control
using System.Windows.Controls;
The Slider control
using System.Windows.Data;
The ProgressBar control
using System.Windows.Documents;
The WebBrowser control
using System.Windows.Media;
The WindowsFormsHost
control
namespace WpfTutorialSamples.ListView_control
{
public partial class ListViewColumnSortingSample :
Window The TabControl
{ Using the TabControl
private GridViewColumnHeader Tab positions
listViewSortCol = null; Styling the TabItems
private SortAdorner listViewSortAdorner =
null;
List controls
public ListViewColumnSortingSample()
The ItemsControl
{
The ListBox control
InitializeComponent();
The ComboBox control
List<User> items = new List<User>
();
items.Add(new User() { Name =
The ListView control
"John Doe", Age = 42, Sex = SexType.Male });
items.Add(new User() { Name = Introduction
"Jane Doe", Age = 39, Sex = SexType.Female }); A simple ListView
items.Add(new User() { Name = ListView, data binding and
"Sammy Doe", Age = 13, Sex = SexType.Male }); ItemTemplate
items.Add(new User() { Name = ListView with a GridView
"Donna Doe", Age = 13, Sex = SexType.Female }); How-to: Left aligned column
lvUsers.ItemsSource = items; names
} ListView grouping
ListView sorting
private void How-to: ListView with
lvUsersColumnHeader_Click(object sender, RoutedEventArgs column sorting
e) ListView filtering
{
GridViewColumnHeader column =
(sender as GridViewColumnHeader); The TreeView control
string sortBy = Introduction
column.Tag.ToString(); A simple TreeView
if(listViewSortCol != null) TreeView, data binding and
{ multiple templates
Handling
AdornerLayer.GetAdornerLayer(listViewSortCol).Remove(listVie Selection/Expansion state
Lazy loading TreeView items
lvUsers.Items.SortDescriptions.Clear();
}
The DataGrid control
Introduction
ListSortDirection newDir =
Custom columns
ListSortDirection.Ascending;
Details row
if(listViewSortCol == column &&
listViewSortAdorner.Direction == newDir)
newDir =
ListSortDirection.Descending; Styles
Introduction
listViewSortCol = column; Using styles
listViewSortAdorner = new Triggers
SortAdorner(listViewSortCol, newDir); Multi triggers
Trigger animations
AdornerLayer.GetAdornerLayer(listViewSortCol).Add(listViewSo
Misc.
lvUsers.Items.SortDescriptions.Add(new
The DispatcherTimer
SortDescription(sortBy, newDir));
}
}
Audio & Video
public enum SexType { Male, Female }; Playing audio
Playing video
public class User How-to: Complete media
{ player
public string Name { get; set; } Speech synthesis
Speech recognition
public int Age { get; set; }
4 Z");
if(AdornedElement.RenderSize.Width
< 20)
return;
drawingContext.Pop();
}
}
}
Allow me to start from the bottom and then work my way up while explaining
what happens. The last class in the file is an Adorner class called
SortAdorner. All this little class does is to draw a triangle, either pointing up
or down, depending on the sort direction. WPF uses the
concept of adorners
to allow you to paint stuff over other controls, and this is exactly what we
want here: The ability to draw a sorting triangle on top
of our ListView column
header.
The SortAdorner works by defining two Geometry objects, which are
basically used to describe 2D shapes - in this case a
triangle with the tip
pointing up and one with the tip pointing down. The Geometry.Parse()
method uses the list of points to draw the triangles, which will
be explained
more thoroughly in a later article.
The SortAdorner is aware of the sort direction, because it needs to draw the
proper triangle, but is not aware of the field that we order
by - this is handled
in the UI layer.
The User class is just a basic information class, used to contain information
about a user. Some of this information is used in the UI
layer, where we bind
to the Name, Age and Sex properties.
In the Window class, we have two methods: The constructor where we build
a list of users and assign it to the ItemsSource of our ListView, and then the
more interesting click event handler that will be hit when the user clicks a
column. In the top of the class, we have defined two private variables:
listViewSortCol and listViewSortAdorner. These will help us keep track of
which column we're currently sorting by and the adorner we
placed to
indicate it.
In the lvUsersColumnHeader_Click event handler, we start off by getting a
reference to the column that the user clicked. With this, we can decide which
property on the User class to sort by, simply by looking at the Tag property
that we defined in XAML. We then check if we're already sorting by a column
-
if that is the case, we remove the adorner and clear the current sort
descriptions.
After that, we're ready to decide the direction. The default is ascending, but
we do a check to see if we're already sorting by the column that the user
clicked - if that is the case, we change the direction to descending.
In the end, we create a new SortAdorner, passing in the column that it should
be rendered on, as well as the direction. We add this to the AdornerLayer of
the column header, and at the very end, we add a SortDescription to the
ListView, to let it know which property to sort by and in which direction.
Summary
Congratulations, you now have a fully sortable ListView with visual indication
of sort column and direction. In case you want to know more about some of
the concepts used in this article, like data binding, geometry or ListViews in
general, then please check out some of the other articles, where each of the
subjects are covered in depth.
Previous Next
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
ListView filtering
Download this entire
tutorial as PDF right
now!
We've already done several different things with the ListView, like grouping About WPF
and sorting, but another very useful ability is filtering. Obviously, you
could
What is WPF?
just limit the items you add to the ListView in the first place, but often you
WPF vs. WinForms
would need to filter the ListView dynamically, in runtime, usually
based on a
user entered filter string. Luckily for us, the view mechanisms of the ListView
also make it easy to do just that, like we saw it with sorting
and grouping.
Getting started
Filtering is actually quite easy to do, so let's jump straight into an example, Visual Studio Express
and then we'll discuss it afterwards: Hello, WPF!
<Window
x:Class="WpfTutorialSamples.ListView_control.FilteringSample XAML
What is XAML?
Basic XAML
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
Events in XAML
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
A WPF application
Title="FilteringSample" Height="200" Width="300">
<DockPanel Margin="10"> Introduction
<TextBox DockPanel.Dock="Top" Margin="0,0,0,10" The Window
Name="txtFilter" TextChanged="txtFilter_TextChanged" /> Working with App.xaml
<ListView Name="lvUsers"> Command-line parameters
<ListView.View> Resources
<GridView> Handling exceptions
<GridViewColumn Header="Name"
Width="120" DisplayMemberBinding="{Binding Name}" />
<GridViewColumn Header="Age" Basic controls
Width="50" DisplayMemberBinding="{Binding Age}" /> The TextBlock control
</GridView> The TextBlock control - Inline
</ListView.View> formatting
</ListView> The Label control
</DockPanel> The TextBox control
</Window> The CheckBox control
using System;
using System.Collections.Generic;
using System.Windows; Panels
using System.Windows.Data; Introduction to WPF Panels
The Canvas
namespace WpfTutorialSamples.ListView_control The WrapPanel
{ The StackPanel
public partial class FilteringSample : Window The DockPanel
{ The Grid
public FilteringSample() The Grid - Rows & Columns
{ The Grid - Units
InitializeComponent(); The Grid - Spanning
List<User> items = new List<User> The Grid - GridSplitter
(); Using the Grid: A contact
items.Add(new User() { Name = form
"John Doe", Age = 42 });
items.Add(new User() { Name =
"Jane Doe", Age = 39 }); Data binding
items.Add(new User() { Name =
Introduction
"Sammy Doe", Age = 13 });
Hello, bound world!
items.Add(new User() { Name =
Using the DataContext
"Donna Doe", Age = 13 });
The UpdateSourceTrigger
lvUsers.ItemsSource = items;
property
Responding to changes
CollectionView view =
Value conversion with
(CollectionView)CollectionViewSource.GetDefaultView(lvUsers.
IValueConverter
The StringFormat property
view.Filter = UserFilter;
Debugging data bindings
}
}
Rich Text controls
}
Introduction
public enum SexType { Male, Female }; The
FlowDocumentScrollViewer
public class User control
{ The
public string Name { get; set; } FlowDocumentPageViewer
control
public int Age { get; set; } The FlowDocumentReader
control
public string Mail { get; set; } Creating a FlowDocument
from Code-behind
public SexType Sex { get; set; } Advanced FlowDocument
} content
} The RichTextBox control
Misc. controls
The Border control
The Slider control
The ProgressBar control
The WebBrowser control
The WindowsFormsHost
control
The TabControl
Using the TabControl
The XAML part is pretty simple: We have a TextBox, where the user can Tab positions
enter a search string, and then a ListView to show the result in. Styling the TabItems
In Code-behind, we start off by adding some User objects to the ListView,
just like we did in previous examples. The interesting part happens in the last
List controls
two lines of the constructor, where we obtain a reference to the
CollectionView instance for the ListView and then assign a delegate to
the The ItemsControl
Filter property. This delegate points to the function called UserFilter, which The ListBox control
we have implemented just below. It
takes each item as the first (and only) The ComboBox control
parameter and then returns a boolean value that indicates whether or not the
given item should be visible on the
list.
The ListView control
In the UserFilter() method, we take a look at the TextBox control (txtFilter), Introduction
to see if it contains any text - if it does, we use it to
check whether or not the A simple ListView
name of the User (which is the property we have decided to filter on) contains ListView, data binding and
the entered string, and then return true or false
depending on that. If the ItemTemplate
TextBox is empty, we return true, because in that case we want all the items ListView with a GridView
to be visible. How-to: Left aligned column
names
The txtFilter_TextChanged event is also important. Each time the text
ListView grouping
changes, we get a reference to the View object of the ListView and then call
ListView sorting
the
Refresh() method on it. This ensures that the Filter delegate is called
How-to: ListView with
each time the user changes the value of the search/filter string text box.
column sorting
Summary ListView filtering
This was a pretty simple implementation, but since you get access to each
item, in this case of the User class, you can do any sort of custom filtering The TreeView control
that you like, since you have access to all of the data about each of the items
Introduction
in the list. For instance, the above example could easily be changed to
filter
A simple TreeView
on age, by looking at the Age property instead of the Name property, or you
TreeView, data binding and
could modify it to look at more than one property, e.g. to filter out
users with
multiple templates
an age below X AND a name that doesn't contain "Y".
Handling
Selection/Expansion state
Previous Next Lazy loading TreeView items
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
TreeView introduction
Download this entire
tutorial as PDF right
now!
The TreeView control enabled you to display hierarchical data, with each About WPF
piece of data represented by a node in the tree. Each node can then have
What is WPF?
child
nodes, and the child nodes can have child nodes and so on. If you have
WPF vs. WinForms
ever used the Windows Explorer, you also know how a TreeView looks - it's
the
control that shows the current folder structure on your machine, in the left
part of the Windows Explorer window.
Getting started
TreeView in WPF vs. WinForms Visual Studio Express
Hello, WPF!
If you have previously worked with the TreeView control in WinForms, you
might think of the TreeView control as one that's easy to use but hard to
customize. In WPF it's a little bit the other way around, at least for newbies: It
XAML
feels a bit complicated to get started with, but it's a LOT easier to
customize.
Just like most other WPF controls, the TreeView is almost lookless once you What is XAML?
start, but it can be styled almost endlessly without much effort. Basic XAML
Events in XAML
Just like with the ListView control, the TreeView control does have its own
item type, the TreeViewItem, which you can use to populate the TreeView. If
you
come from the WinForms world, you will likely start by generating A WPF application
TreeViewItem's and adding them to the Items property, and this is indeed
Introduction
possible. But
since this is WPF, the preferred way is to bind the TreeView to
The Window
a hierarchical data structure and then use an appropriate template to render
Working with App.xaml
the content.
Command-line parameters
We'll show you how to do it both ways, and while the good, old WinForms Resources
inspired way might seem like the easy choice at first, you should definitely Handling exceptions
give
the WPF way a try - in the long run, it offers more flexibility and will fit in
better with the rest of the WPF code you write.
Basic controls
Summary The TextBlock control
The TextBlock control - Inline
The WPF TreeView is indeed a complex control. In the first example, which
formatting
we'll get into already in the next chapter, it might seem simple, but once you
The Label control
dig deeper, you'll see the complexity. Fortunately, the WPF TreeView control
The TextBox control
rewards you with great usability and flexibility. To show you all of them,
we
The CheckBox control
have dedicated an entire category to all the TreeView articles. Click on to the
Previous Next
Panels
Introduction to WPF Panels
The Canvas
comments powered by Disqus
The WrapPanel
The StackPanel
The DockPanel
The Grid
The Grid - Rows & Columns
The Grid - Units
The Grid - Spanning
The Grid - GridSplitter
Using the Grid: A contact
form
Data binding
Introduction
Hello, bound world!
Using the DataContext
The UpdateSourceTrigger
property
Responding to changes
Value conversion with
IValueConverter
The StringFormat property
Debugging data bindings
Commands
Introduction
Using commands
Implementing custom
commands
Common interface
controls
The Menu control
The ContextMenu
The ToolBar control
The StatusBar control
The Ribbon Control
Introduction
The
FlowDocumentScrollViewer
control
The
FlowDocumentPageViewer
control
The FlowDocumentReader
control
Creating a FlowDocument
from Code-behind
Advanced FlowDocument
content
The RichTextBox control
Misc. controls
The Border control
The Slider control
The ProgressBar control
The WebBrowser control
The WindowsFormsHost
control
The TabControl
Using the TabControl
Tab positions
Styling the TabItems
List controls
The ItemsControl
The ListBox control
The ComboBox control
ListView filtering
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
A simple TreeView example
Download this entire
tutorial as PDF right
now!
As we talked about in the previous article, the WPF TreeView can be used in About WPF
a very simple manner, by adding TreeViewItem objects to it, either from
What is WPF?
Code-behind or simply by declaring them directly in your XAML. This is
WPF vs. WinForms
indeed very easy to get started with, as you can see from the example here:
<Window
Getting started
x:Class="WpfTutorialSamples.TreeView_control.TreeViewSample"
Visual Studio Express
Hello, WPF!
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
XAML
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" What is XAML?
Title="TreeViewSample" Height="200" Width="250"> Basic XAML
<Grid Margin="10"> Events in XAML
<TreeView>
<TreeViewItem Header="Level 1"
IsExpanded="True">
A WPF application
<TreeViewItem
Introduction
Header="Level 2.1" />
The Window
<TreeViewItem
Working with App.xaml
Header="Level 2.2" IsExpanded="True">
Command-line parameters
<TreeViewItem
Resources
Header="Level 3.1" />
Handling exceptions
<TreeViewItem
Header="Level 3.2" />
</TreeViewItem>
<TreeViewItem Basic controls
Header="Level 2.3" /> The TextBlock control
</TreeViewItem> The TextBlock control - Inline
</TreeView> formatting
</Grid> The Label control
</Window> The TextBox control
The CheckBox control
Panels
Introduction to WPF Panels
The Canvas
The WrapPanel
The StackPanel
The DockPanel
The Grid
The Grid - Rows & Columns
We simply declare the TreeViewItem objects directly in the XAML, in the The Grid - Units
same structure that we want to display them in, where the first tag is a child The Grid - Spanning
of
the TreeView control and its child objects are also child tags to its parent The Grid - GridSplitter
object. To specify the text we want displayed for each node, we use Using the Grid: A contact
theHeader property. By default, a TreeViewItem is not expanded, but to form
show you the structure of the example, I have used the IsExpanded property
to expand the two parent items.
Data binding
TreeViewItem's with images and other Introduction
controls Hello, bound world!
The Header is an interesting property, though. As you can see, I can just Using the DataContext
specify a text string and then have it rendered directly without
doing anything The UpdateSourceTrigger
else, but this is WPF being nice to us - internally, it wraps the text inside of a property
TextBlock control, instead of forcing you to do it. This
shows us that we can Responding to changes
stuff pretty much whatever we want to into the Header property instead of Value conversion with
just a string and then have the TreeView render it - a great
example of why IValueConverter
it's so easy to customize the look of WPF controls. The StringFormat property
Debugging data bindings
One of the common requests from people coming from WinForms or even
other UI libraries is the ability to show an image next to the text label of a
TreeView
item. This is very easy to do with WinForms, because the Commands
TreeView is built exactly for this scenario. With the WPF TreeView, it's a bit
Introduction
more complex, but
you're rewarded with a lot more flexibility than you could
Using commands
ever get from the WinForms TreeView. Here's an example of it:
Implementing custom
commands
<Window
x:Class="WpfTutorialSamples.TreeView_control.TreeViewCustomI
Common interface
controls
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
The Menu control
The ContextMenu
The ToolBar control
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
The StatusBar control
Title="TreeViewCustomItemsSample" Height="200"
The Ribbon Control
Width="250">
<Grid Margin="10">
<TreeView>
<TreeViewItem IsExpanded="True"> Rich Text controls
<TreeViewItem.Header> Introduction
<StackPanel The
Orientation="Horizontal"> FlowDocumentScrollViewer
<Image control
Source="/WpfTutorialSamples;component/Images/bullet_blue.png The
/> FlowDocumentPageViewer
<TextBlock control
Text="Level 1 (Blue)" /> The FlowDocumentReader
</StackPanel> control
</TreeViewItem.Header> Creating a FlowDocument
<TreeViewItem> from Code-behind
Advanced FlowDocument
<TreeViewItem.Header> content
The RichTextBox control
<StackPanel Orientation="Horizontal">
<TextBlock Text="Level 2.1" Foreground="Blue" /> Misc. controls
The Border control
</StackPanel>
The Slider control
The ProgressBar control
</TreeViewItem.Header>
The WebBrowser control
</TreeViewItem>
The WindowsFormsHost
<TreeViewItem
control
IsExpanded="True">
<TreeViewItem.Header>
The TabControl
<StackPanel Orientation="Horizontal"> Using the TabControl
Tab positions
<Image Styling the TabItems
Source="/WpfTutorialSamples;component/Images/bullet_green.pn
/>
List controls
<TextBlock Text="Level 2.2 (Green)" Foreground="Blue" />
The ItemsControl
The ListBox control
</StackPanel>
The ComboBox control
</TreeViewItem.Header>
<TreeViewItem>
The ListView control
<TreeViewItem.Header> Introduction
A simple ListView
<TextBlock Text="Level 3.1" Foreground="Green" /> ListView, data binding and
ItemTemplate
</TreeViewItem.Header> ListView with a GridView
</TreeViewItem> How-to: Left aligned column
<TreeViewItem> names
ListView grouping
<TreeViewItem.Header> ListView sorting
How-to: ListView with
<TextBlock Text="Level 3.2" Foreground="Green" /> column sorting
ListView filtering
</TreeViewItem.Header>
</TreeViewItem>
</TreeViewItem> The TreeView control
<TreeViewItem> Introduction
A simple TreeView
<TreeViewItem.Header> TreeView, data binding and
<TextBlock multiple templates
Text="Level 2.3" Foreground="Blue" /> Handling
Selection/Expansion state
</TreeViewItem.Header> Lazy loading TreeView items
</TreeViewItem>
</TreeViewItem>
</TreeView>
The DataGrid control
</Grid>
Introduction
</Window>
Custom columns
Details row
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
I did a whole bunch of things here, just to show you the kind of flexibility you The DispatcherTimer
get: I colored the child items and I added images and even buttons to the
parent items. Because we're defining the entire thing with simple markup,
you can do almost anything, but as you can see from the example code, it Audio & Video
does
come with a price: Huge amounts of XAML code, for a tree with just six Playing audio
nodes in total! Playing video
How-to: Complete media
Summary player
While it is entirely possible to define an entire TreeView just using markup, as Speech synthesis
we did in the above examples, it's not the best approach in most
situations, Speech recognition
and while you could do it from Code-behind instead, this would have resulted
in even more lines of code. Once again the solution is data binding, which
we'll look into in the next chapters.
Previous Next
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
TreeView, data binding and multiple
templates Download this entire
tutorial as PDF right
now!
About WPF
The WPF TreeView supports data binding, like pretty much all other WPF
What is WPF?
controls does, but because the TreeView is hierarchical in nature, a normal
WPF vs. WinForms
DataTemplate often won't suffice. Instead, we use the
HierarchicalDataTemplate, which allows us to template both the tree node
itself, while controlling
which property to use as a source for child items of the
node. Getting started
Visual Studio Express
A basic data bound TreeView Hello, WPF!
In the following example, I'll show you just how easy it is to get started with
the HierarchicalDataTemplate:
XAML
What is XAML?
<Window
Basic XAML
x:Class="WpfTutorialSamples.TreeView_control.TreeViewDataBin
Events in XAML
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
A WPF application
Introduction
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" The Window
xmlns:self="clr- Working with App.xaml
namespace:WpfTutorialSamples.TreeView_control" Command-line parameters
Title="TreeViewDataBindingSample" Height="150" Resources
Width="200"> Handling exceptions
<Grid Margin="10">
<TreeView Name="trvMenu">
<TreeView.ItemTemplate> Basic controls
<HierarchicalDataTemplate
The TextBlock control
DataType="{x:Type self:MenuItem}" ItemsSource="{Binding
The TextBlock control - Inline
Items}">
formatting
<TextBlock Text="
The Label control
{Binding Title}" />
The TextBox control
The CheckBox control
</HierarchicalDataTemplate>
Introduction
The
FlowDocumentScrollViewer
control
The
FlowDocumentPageViewer
control
The FlowDocumentReader
control
Creating a FlowDocument
In the XAML markup, I have specified a HierarchicalDataTemplate for the from Code-behind
ItemTemplate of the TreeView. I instruct it to use the Items property for Advanced FlowDocument
finding child items, by setting the ItemsSource property of the template, and content
inside of it I define
the actual template, which for now just consists of a The RichTextBox control
TextBlock bound to the Title property.
This first example was very simple, in fact so simple that we might as well Misc. controls
have just added the TreeView items manually, instead of generating a set of
The Border control
objects and then binding to them. However, as soon as things get a bit more
The Slider control
complicated, the advantages of using data bindings gets more obvious.
The ProgressBar control
Multiple templates for different types The WebBrowser control
The WindowsFormsHost
In the next example, I've taken a slightly more complex case, where I want to control
show a tree of families and their members. A family should be represented in
one way, while each of its members should be shown in another way. I
achieve this by creating two different templates and specifying them as The TabControl
resources of
the tree (or the Window or the Application - that's really up to
Using the TabControl
you), and then allowing the TreeView to pick the correct template based on
Tab positions
the underlying
type of data.
Styling the TabItems
Here's the code - the explanation of it will follow right after:
List controls
<Window
x:Class="WpfTutorialSamples.TreeView_control.TreeViewMultipl The ItemsControl
The ListBox control
The ComboBox control
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
ListView filtering
Orientation="Horizontal">
<Image
Source="/WpfTutorialSamples;component/Images/group.png"
The TreeView control
Margin="0,0,5,0" />
<TextBlock Introduction
Text="{Binding Name}" /> A simple TreeView
<TextBlock TreeView, data binding and
Text=" [" Foreground="Blue" /> multiple templates
<TextBlock Handling
Text="{Binding Members.Count}" Foreground="Blue" /> Selection/Expansion state
<TextBlock Lazy loading TreeView items
Text="]" Foreground="Blue" />
</StackPanel>
The DataGrid control
</HierarchicalDataTemplate> Introduction
<DataTemplate DataType=" Custom columns
{x:Type self:FamilyMember}"> Details row
<StackPanel
Orientation="Horizontal">
<Image Styles
Source="/WpfTutorialSamples;component/Images/user.png"
Introduction
Margin="0,0,5,0" />
Using styles
<TextBlock
Triggers
Text="{Binding Name}" />
Multi triggers
<TextBlock
Trigger animations
Text=" (" Foreground="Green" />
<TextBlock
Text="{Binding Age}" Foreground="Green" />
<TextBlock Misc.
Text=" years)" Foreground="Green" /> The DispatcherTimer
</StackPanel>
</DataTemplate>
</TreeView.Resources> Audio & Video
</TreeView>
Playing audio
</Grid>
Playing video
</Window>
How-to: Complete media
player
Speech synthesis
using System; Speech recognition
using System.Collections.Generic;
using System.Windows;
using System.Collections.ObjectModel;
namespace WpfTutorialSamples.TreeView_control
{
public partial class
TreeViewMultipleTemplatesSample : Window
{
public TreeViewMultipleTemplatesSample()
{
InitializeComponent();
trvFamilies.ItemsSource =
families;
}
}
public ObservableCollection<FamilyMember>
Members { get; set; }
}
As mentioned, the two templates are declared as a part of the TreeView
resources, allowing the TreeView to select the appropriate template based on
the
data type that it's about to show. The template defined for the Family
type is a hierarchical template, using the Members
property to show its
family members.
The template defined for the FamilyMember type is a regular DataTemplate,
since this type doesn't have any child members. However, if we
had wanted
each FamilyMember to keep a collection of their children and perhaps their
children's children, then we would have used a hierarchical template
instead.
In both templates, we use an image representing either a family or a family
member, and then we show some interesting data about it as well, like the
amount of family members or the person's age.
In the code-behind, we simply create two Family instances, fill each of them
with a set of members, and then add each of the families to a list, which is
then used as the items source for the TreeView.
Summary
Using data binding, the TreeView is very customizable and with the ability to
specify multiple templates for rendering different data types, the
possibilities
are almost endless.
Previous Next
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
TreeView - Selection/Expansion state
Download this entire
tutorial as PDF right
now!
In the previous couple of TreeView articles, we used data binding to display About WPF
custom objects in a WPF TreeView. This works really well, but it does leave
What is WPF?
you with one problem: Because each tree node is now represented by your
WPF vs. WinForms
custom class, for instance FamilyMember as we saw in the previous article,
you no
longer have direct control over TreeView node specific functionality
like selection and expansion state. In praxis this means that you can't select
or
expand/collapse a given node from code-behind. Getting started
Visual Studio Express
Lots of solutions exists to handle this, ranging from "hacks" where you use Hello, WPF!
the item generators of the TreeView to get the underlying TreeViewItem,
where
you can control the IsExpanded and IsSelected properties, to much
more advanced MVVM-inspired implementations. In this article I would like to
XAML
show you a
solution that lies somewhere in the middle, making it easy to
What is XAML?
implement and use, while still not being a complete hack.
Basic XAML
A TreeView selection/expansion solution Events in XAML
The basic principle is to implement two extra properties on your data class:
IsExpanded and IsSelected. These two properties are then hooked up to the A WPF application
TreeView, using a couple of styles targeting the TreeViewItem, inside of the
Introduction
ItemContainerStyle for the TreeView.
The Window
You could easily implement these two properties on all of your objects, but Working with App.xaml
it's much easier to inherit them from a base object. If this is not feasible
for Command-line parameters
your solution, you could create an interface for it and then implement this Resources
instead, to establish a common ground. For this example, I've chosen the Handling exceptions
base class method, because it allows me to very easily get the same
functionality for my other objects. Here's the code:
Basic controls
<Window The TextBlock control
x:Class="WpfTutorialSamples.TreeView_control.TreeViewSelecti The TextBlock control - Inline
formatting
The Label control
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta The TextBox control
The CheckBox control
Introduction
namespace WpfTutorialSamples.TreeView_control
The
{
FlowDocumentScrollViewer
public partial class
control
TreeViewSelectionExpansionSample : Window
The
{
FlowDocumentPageViewer
public TreeViewSelectionExpansionSample()
control
{
The FlowDocumentReader
InitializeComponent();
control
Creating a FlowDocument
List<Person> persons = new
from Code-behind
List<Person>();
Advanced FlowDocument
Person person1 = new Person() {
content
Name = "John Doe", Age = 42 };
The RichTextBox control
List controls
person2.IsExpanded = true;
The ItemsControl
person2.IsSelected = true;
The ListBox control
The ComboBox control
trvPersons.ItemsSource = persons;
}
} Styles
Introduction
public class Person : TreeViewItemBase
Using styles
{
Triggers
public Person()
Multi triggers
{
Trigger animations
this.Children = new
ObservableCollection<Person>();
}
Misc.
public string Name { get; set; } The DispatcherTimer
value;
NotifyPropertyChanged("IsSelected");
}
}
}
I'm sorry for the rather large amount of code in one place. In a real world
solution, it would obviously be spread out over multiple files instead and the
data for the tree would likely come from an actual data source, instead of
being generated on the fly. Allow me to explain what happens in the
example.
XAML part
I have defined a couple of buttons to be placed in the bottom of the dialog, to
use the two new properties. Then we have the TreeView, for which I have
defined an ItemTemplate (as demonstrated in a previous chapter) as well as
an ItemContainerStyle. If you haven't read the chapters on styling yet, you
might not completely understand that part, but it's simply a matter of tying
together the properties on our own custom class with the IsSelected and
IsExpanded properties on the TreeViewItems, which is done with Style
setters. You can learn more about
them elsewhere in this tutorial.
Code-behind part
In the code-behind, I have defined a Person class, with a couple of
properties, which inherits our extra properties from the TreeViewItemBase
class. You should be aware that the TreeViewItemBase class implements the
INotifyPropertyChanged interface and uses it to
notify of changes to these
two essential properties - without this, selection/expansion changes won't be
reflected in the UI. The concept of notification
changes are explained in the
Data binding chapters.
In the main Window class I simply create a range of persons, while adding
children to some of them. I add the persons to a list, which I assign as the
ItemsSource of the TreeView, which, with a bit of help from the defined
template, renders them the way they are shown on the screenshot.
The most interesting part happens when I set the IsExpanded and IsSelected
properties on the person2 object. This is what causes the second person
(Jane Doe) to be initially selected and expanded, as shown on the
screenshot. We also use these two properties on the Person objects
(inherited from the
TreeViewItemBase class) in the event handlers for the two
test buttons (please bear in mind that, to keep the code as small and simple
as possible, the
selection button only works for the top level items).
Summary
By creating and implementing a base class for the objects that you wish to
use and manipulate within a TreeView, and using the gained properties in the
ItemContainerStyle, you make it a lot easier to work with selections and
expansion states. There are many solutions to tackle this problem with, and
while
this should do the trick, you might be able to find a solution that fits your
needs better. As always with programming, it's all about using the right tool
for the job at hand.
Previous Next
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
Lazy loading TreeView items
Download this entire
tutorial as PDF right
now!
The usual process when using the TreeView is to bind to a collection of items About WPF
or to manually add each level at the same time. However, in some situations,
What is WPF?
you want to delay the loading of a nodes child items until they are actually
WPF vs. WinForms
needed. This is especially useful if you have a very deep tree, with lots of
levels and child nodes and a great example of this, is the folder structure of
your Windows computer.
Getting started
Each drive on your Windows computer has a range of child folders, and each Visual Studio Express
of those child folders have child folders beneath them and so on. Looping Hello, WPF!
through each drive and each drives child folders could become extremely
time consuming and your TreeView would soon consist of a lot of nodes, with
a high
percentage of them never being needed. This is the perfect task for a
XAML
lazy-loaded TreeView, where child folders are only loaded on demand.
What is XAML?
To achieve this, we simply add a dummy folder to each drive or child folder, Basic XAML
and then when the user expands it, we remove the dummy folder and replace Events in XAML
it
with the actual values. This is how our application looks when it starts - by
that time, we have only obtained a list of available drives on the computer:
A WPF application
Introduction
The Window
Working with App.xaml
Command-line parameters
Resources
Handling exceptions
Basic controls
The TextBlock control
The TextBlock control - Inline
formatting
The Label control
The TextBox control
The CheckBox control
You can now start expanding the nodes, and the application will The RadioButton control
automatically load the sub folders. If a folder is empty, it will be shown as The PasswordBox control
empty once
you try to expand it, as it can be seen on the next screenshot:
Panels
Introduction to WPF Panels
The Canvas
The WrapPanel
The StackPanel
The DockPanel
The Grid
The Grid - Rows & Columns
The Grid - Units
The Grid - Spanning
The Grid - GridSplitter
Using the Grid: A contact
form
So how is it accomplished? Let's have a look at the code: Data binding
Introduction
<Window Hello, bound world!
x:Class="WpfTutorialSamples.TreeView_control.LazyLoadingSamp Using the DataContext
The UpdateSourceTrigger
property
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta Responding to changes
Value conversion with
IValueConverter
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" The StringFormat property
Title="LazyLoadingSample" Height="300" Debugging data bindings
Width="300">
<Grid>
<TreeView Name="trvStructure" Commands
TreeViewItem.Expanded="TreeViewItem_Expanded" Margin="10"
Introduction
/>
Using commands
</Grid>
Implementing custom
</Window>
commands
InitializeComponent(); Introduction
DriveInfo[] drives = The
DriveInfo.GetDrives(); FlowDocumentScrollViewer
foreach(DriveInfo driveInfo in control
drives) The
FlowDocumentPageViewer
trvStructure.Items.Add(CreateTreeItem(driveInfo)); control
} The FlowDocumentReader
control
public void TreeViewItem_Expanded(object Creating a FlowDocument
sender, RoutedEventArgs e) from Code-behind
{ Advanced FlowDocument
TreeViewItem item = e.Source as content
TreeViewItem; The RichTextBox control
if((item.Items.Count == 1) &&
(item.Items[0] is string))
{ Misc. controls
item.Items.Clear(); The Border control
The Slider control
DirectoryInfo expandedDir The ProgressBar control
= null; The WebBrowser control
if(item.Tag is DriveInfo) The WindowsFormsHost
expandedDir = control
(item.Tag as DriveInfo).RootDirectory;
if(item.Tag is
DirectoryInfo) The TabControl
expandedDir =
Using the TabControl
(item.Tag as DirectoryInfo);
Tab positions
try
Styling the TabItems
{
foreach(DirectoryInfo subDir in
expandedDir.GetDirectories()) List controls
The ItemsControl
item.Items.Add(CreateTreeItem(subDir)); The ListBox control
} The ComboBox control
catch { }
}
} The ListView control
Introduction
private TreeViewItem CreateTreeItem(object
A simple ListView
o)
ListView, data binding and
{
ItemTemplate
TreeViewItem item = new
ListView with a GridView
TreeViewItem();
How-to: Left aligned column
item.Header = o.ToString();
names
item.Tag = o;
ListView grouping
item.Items.Add("Loading...");
ListView sorting
return item;
How-to: ListView with
}
column sorting
}
ListView filtering
}
The XAML is very simple and only one interesting detail is present: The way The TreeView control
we subscribe to the Expanded event of TreeViewItem's. Notice
that this is
Introduction
indeed the TreeViewItem and not the TreeView itself, but because the event
A simple TreeView
bubbles up, we are able to just capture it in one place for the
entire
TreeView, data binding and
TreeView, instead of having to subscribe to it for each item we add to the
multiple templates
tree. This event gets called each time an item is expanded, which we need
to
Handling
be aware of to load its child items on demand.
Selection/Expansion state
In Code-behind, we start by adding each drive found on the computer to the Lazy loading TreeView items
TreeView control. We assign the DriveInfo
instance to the Tag property, so
that we can later retrieve it. Notice that we use a custom method to create
the TreeViewItem, called CreateTreeItem(), since we can use the exact The DataGrid control
same method when we want to dynamically add a child folder later on. Notice Introduction
in this method
how we add a child item to the Items collection, in the form of Custom columns
a string with the text "Loading...". Details row
Next up is the TreeViewItem_Expanded event. As already mentioned, this
event is raised each time a TreeView item is expanded, so the first thing we
Styles
do is
to check whether this item has already been loaded, by checking if the
child items currently consists of only one item, which is a string - if so, we Introduction
have
found the "Loading..." child item, which means that we should now load Using styles
the actual contents and replace the placeholder item with it. Triggers
Multi triggers
We now use the items Tag property to get a reference to the DriveInfo or Trigger animations
DirectoryInfo instance that the current item
represents, and then we get a
list of child directories, which we add to the clicked item, once again using the
CreateTreeItem() method.
Notice that the loop where we add each child Misc.
folder is in a try..catch block - this is important, because some paths might
The DispatcherTimer
not be accessible, usually for
security reasons. You could grab the exception
and use it to reflect this in the interface in one way or another.
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
The DataGrid control
Download this entire
tutorial as PDF right
now!
The DataGrid control looks a lot like the ListView, when using a GridView, but About WPF
it offers a lot of additional functionality. For instance, the DataGrid can
What is WPF?
automatically generate columns, depending on the data you feed it with. The
WPF vs. WinForms
DataGrid is also editable by default, allowing the end-user to change the
values of the underlying data source.
The most common usage for the DataGrid is in combination with a database, Getting started
but like most WPF controls, it works just as well with an in-memory source, Visual Studio Express
like
a list of objects. Since it's a lot easier to demonstrate, we'll mostly be Hello, WPF!
using the latter approach in this tutorial.
A simple DataGrid XAML
You can start using the DataGrid without setting any properties, because it What is XAML?
supports so much out of the box. In this first example, we'll do just that, and Basic XAML
then assign a list of our own User objects as the items source: Events in XAML
<Window
x:Class="WpfTutorialSamples.DataGrid_control.SimpleDataGridS A WPF application
Introduction
The Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta Working with App.xaml
Command-line parameters
Resources
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Handling exceptions
Title="SimpleDataGridSample" Height="180"
Width="300">
<Grid Margin="10">
Basic controls
<DataGrid Name="dgSimple"></DataGrid>
</Grid> The TextBlock control
</Window> The TextBlock control - Inline
formatting
The Label control
The TextBox control
using System; The CheckBox control
namespace WpfTutorialSamples.DataGrid_control
{ Panels
public partial class SimpleDataGridSample : Window
Introduction to WPF Panels
{
The Canvas
public SimpleDataGridSample()
The WrapPanel
{
The StackPanel
InitializeComponent();
The DockPanel
The Grid
List<User> users = new List<User>
The Grid - Rows & Columns
();
The Grid - Units
users.Add(new User() { Id = 1,
The Grid - Spanning
Name = "John Doe", Birthday = new DateTime(1971, 7, 23)
The Grid - GridSplitter
});
Using the Grid: A contact
users.Add(new User() { Id = 2,
form
Name = "Jane Doe", Birthday = new DateTime(1974, 1, 17)
});
users.Add(new User() { Id = 3,
Name = "Sammy Doe", Birthday = new DateTime(1991, 9, 2)
Data binding
}); Introduction
Hello, bound world!
dgSimple.ItemsSource = users; Using the DataContext
} The UpdateSourceTrigger
} property
Responding to changes
public class User Value conversion with
{ IValueConverter
public int Id { get; set; } The StringFormat property
Debugging data bindings
public string Name { get; set; }
Common interface
controls
The Menu control
The ContextMenu
The ToolBar control
The StatusBar control
The Ribbon Control
That's really all you need to start using the DataGrid. The source could just
as easily have been a database table/view or even an XML file - the DataGrid Rich Text controls
is not picky about where it gets its data from.
Introduction
If you click inside one of the cells, you can see that you're allowed to edit The
each of the properties by default. As a nice little bonus, you can try
clicking FlowDocumentScrollViewer
one of the column headers - you will see that the DataGrid supports sorting control
right out of the box! The
FlowDocumentPageViewer
The last and empty row will let you add to the data source, simply by filling control
out the cells. The FlowDocumentReader
control
Summary Creating a FlowDocument
from Code-behind
As you can see, it's extremely easy to get started with the DataGrid, but it's
Advanced FlowDocument
also a highly customizable control. In the next chapters, we'll look into
all the
content
cool stuff you can do with the DataGrid, so read on.
The RichTextBox control
Previous Next
Misc. controls
The Border control
The Slider control
comments powered by Disqus The ProgressBar control
The WebBrowser control
The WindowsFormsHost
control
The TabControl
Using the TabControl
Tab positions
Styling the TabItems
List controls
The ItemsControl
The ListBox control
The ComboBox control
ListView filtering
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
DataGrid columns
Download this entire
tutorial as PDF right
now!
In the previous chapter, we had a look at just how easy you could get a WPF About WPF
DataGrid up and running. One of the reasons why it was so easy is the fact
What is WPF?
that
the DataGrid will automatically generate appropriate columns for you,
WPF vs. WinForms
based on the data source you use.
However, in some situations you might want to manually define the columns
shown, either because you don’t want all the properties/columns of the data Getting started
source, or because you want to be in control of which inline editors are used. Visual Studio Express
Hello, WPF!
Manually defined columns
Let's try an example that looks a lot like the one in the previous chapter, but
where we define all the columns manually, for maximum control. You can XAML
select the column type based on the data that you wish to display/edit. As of What is XAML?
writing, the following column types are available: Basic XAML
Events in XAML
DataGridTextColumn
DataGridCheckBoxColumn
DataGridComboBoxColumn
A WPF application
DataGridHyperlinkColumn
DataGridTemplateColumn Introduction
The Window
Especially the last one, the DataGridTemplateColumn, is interesting. It allows Working with App.xaml
you to define any kind of content, which opens up the opportunity to use Command-line parameters
custom controls, either from the WPF library or even your own or 3rd party Resources
controls. Here's an example: Handling exceptions
<Window
x:Class="WpfTutorialSamples.DataGrid_control.DataGridColumns Basic controls
The TextBlock control
The TextBlock control - Inline
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta formatting
The Label control
The TextBox control
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" The CheckBox control
using System;
using System.Collections.Generic;
Commands
using System.Windows;
Introduction
namespace WpfTutorialSamples.DataGrid_control Using commands
{ Implementing custom
public partial class DataGridColumnsSample : commands
Window
{
public DataGridColumnsSample() Common interface
{ controls
InitializeComponent(); The Menu control
The ContextMenu
List<User> users = new List<User> The ToolBar control
(); The StatusBar control
users.Add(new User() { Id = 1, The Ribbon Control
Name = "John Doe", Birthday = new DateTime(1971, 7, 23)
});
users.Add(new User() { Id = 2,
Rich Text controls
The TabControl
Using the TabControl
Tab positions
Styling the TabItems
List controls
The ItemsControl
The ListBox control
The ComboBox control
In the markup, I have added the AutoGenerateColumns property on the
DataGrid, which I have set to false, to get control of the columns used. As
you can
see, I have left out the ID column, as I decided that I didn't care for it
for this example. For the Name property, I've used a simple text based The ListView control
column,
so the most interesting part of this example comes with the Birthday Introduction
column, where I've used a DataGridTemplateColumn with a DatePicker A simple ListView
control inside of
it. This allows the end-user to pick the date from a calendar, ListView, data binding and
instead of having to manually enter it, as you can see on the screenshot. ItemTemplate
ListView with a GridView
Summary How-to: Left aligned column
names
By turning off automatically generated columns using the
ListView grouping
AutoGenerateColumns property, you get full control of which columns are
ListView sorting
shown and how their data
should be viewed and edited. As seen by the
How-to: ListView with
example of this article, this opens up for some pretty interesting possibilities,
column sorting
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
DataGrid with row details
Download this entire
tutorial as PDF right
now!
A very common usage scenario when using a DataGrid control is the ability About WPF
to show details about each row, typically right below the row itself. The WPF
What is WPF?
DataGrid control supports this very well, and fortunately it's also very easy to
WPF vs. WinForms
use. Let's start off with an example and then we'll discuss how it works
and
the options it gives you afterwards:
Getting started
<Window
x:Class="WpfTutorialSamples.DataGrid_control.DataGridDetails Visual Studio Express
Hello, WPF!
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
XAML
What is XAML?
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Basic XAML
Title="DataGridDetailsSample" Height="200" Events in XAML
Width="400">
<Grid Margin="10">
<DataGrid Name="dgUsers"
A WPF application
AutoGenerateColumns="False">
Introduction
<DataGrid.Columns>
The Window
<DataGridTextColumn
Working with App.xaml
Header="Name" Binding="{Binding Name}" />
Command-line parameters
<DataGridTextColumn
Resources
Header="Birthday" Binding="{Binding Birthday}" />
Handling exceptions
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<TextBlock Text=" Basic controls
{Binding Details}" Margin="10" /> The TextBlock control
</DataTemplate> The TextBlock control - Inline
</DataGrid.RowDetailsTemplate> formatting
</DataGrid> The Label control
</Grid> The TextBox control
</Window> The CheckBox control
using System;
using System.Collections.Generic;
Panels
using System.Windows;
Introduction to WPF Panels
namespace WpfTutorialSamples.DataGrid_control The Canvas
{ The WrapPanel
public partial class DataGridDetailsSample : The StackPanel
Window The DockPanel
{ The Grid
public DataGridDetailsSample() The Grid - Rows & Columns
{ The Grid - Units
InitializeComponent(); The Grid - Spanning
List<User> users = new List<User> The Grid - GridSplitter
(); Using the Grid: A contact
users.Add(new User() { Id = 1, form
Name = "John Doe", Birthday = new DateTime(1971, 7, 23)
});
users.Add(new User() { Id = 2, Data binding
Name = "Jane Doe", Birthday = new DateTime(1974, 1, 17) Introduction
}); Hello, bound world!
users.Add(new User() { Id = 3, Using the DataContext
Name = "Sammy Doe", Birthday = new DateTime(1991, 9, 2) The UpdateSourceTrigger
}); property
Responding to changes
dgUsers.ItemsSource = users; Value conversion with
} IValueConverter
} The StringFormat property
Debugging data bindings
public class User
{
public int Id { get; set; }
Commands
public string Name { get; set; } Introduction
Using commands
public DateTime Birthday { get; set; } Implementing custom
commands
public string Details
{
get Common interface
{ controls
return String.Format("{0} The Menu control
was born on {1} and this is a long description of the The ContextMenu
person.", this.Name, this.Birthday.ToLongDateString()); The ToolBar control
} The StatusBar control
} The Ribbon Control
}
}
Introduction
The
FlowDocumentScrollViewer
control
The
FlowDocumentPageViewer
control
The FlowDocumentReader
control
Creating a FlowDocument
from Code-behind
Advanced FlowDocument
content
As you can see, I have expanded the example from previous chapters with a
The RichTextBox control
new property on the User class: The Description property. It simply returns a
bit
of information about the user in question, for our details row.
In the markup, I have defined a couple of columns and then I use the Misc. controls
RowDetailsTemplate to specify a template for the row details. As you
can The Border control
see, it works much like any other WPF template, where I use a DataTemplate The Slider control
with one or several controls inside of it, along with a standard binding
against The ProgressBar control
a property on the data source, in this case the Description property. The WebBrowser control
The WindowsFormsHost
As you can see from the resulting screenshot, or if you run the sample
control
yourself, the details are now shown below the selected row. As soon as you
select
another row, the details for that row will be shown and the details for
the previously selected row will be hidden.
The TabControl
Controlling row details visibility Using the TabControl
Tab positions
Using the RowDetailsVisibilityMode property, you can change the above Styling the TabItems
mentioned behavior though. It defaults toVisibleWhenSelected, where
details are only visible when its parent row is selected, but you can change it
to Visible or Collapsed. If you set it to Visible, all details rows will be visible
List controls
all the time, like this:
The ItemsControl
The ListBox control
The ComboBox control
If you set it to Collapsed, all details will be invisible all the time. ListView filtering
More details
The first example of this article might have been a tad boring, using just a The TreeView control
single, plain TextBlock control. Of course, with this being a DataTemplate, Introduction
you can do pretty much whatever you want, so I decided to extend the A simple TreeView
example a bit, to give a better idea of the possibilities. Here's how it looks TreeView, data binding and
now: multiple templates
Handling
Selection/Expansion state
Lazy loading TreeView items
Styles
Introduction
Using styles
As you can see from the code listing, it's mostly about expanding the details Triggers
template into using a panel, which in turn can host more panels and/or Multi triggers
controls. Using a Grid panel, we can get the tabular look of the user data, Trigger animations
and an Image control allows us to show a picture of the user (which you
should
preferably load from a locale resource and not a remote one, like I do
in the example - and sorry for being too lazy to find a matching image of Jane Misc.
and
Sammy Doe).
The DispatcherTimer
<Window
x:Class="WpfTutorialSamples.DataGrid_control.DataGridDetails
Audio & Video
Playing audio
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta Playing video
How-to: Complete media
player
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Speech synthesis
Title="DataGridDetailsSample" Height="300" Speech recognition
Width="300">
<Grid Margin="10">
<DataGrid Name="dgUsers"
AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn
Header="Name" Binding="{Binding Name}" />
<DataGridTextColumn
Header="Birthday" Binding="{Binding Birthday}" />
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<DockPanel
Background="GhostWhite">
<Image
DockPanel.Dock="Left" Source="{Binding ImageUrl}"
Height="64" Margin="10" />
<Grid
Margin="0,10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Text="ID: " FontWeight="Bold" />
<TextBlock Text="{Binding Id}" Grid.Column="1" />
<TextBlock Text="Name: " FontWeight="Bold" Grid.Row="1" />
<TextBlock Text="{Binding Name}" Grid.Column="1"
Grid.Row="1" />
<TextBlock Text="Birthday: " FontWeight="Bold"
Grid.Row="2" />
<TextBlock Text="{Binding Birthday, StringFormat=d}"
Grid.Column="1" Grid.Row="2" />
</Grid>
</DockPanel>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
</Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Windows;
namespace WpfTutorialSamples.DataGrid_control
{
public partial class DataGridDetailsSample :
Window
{
public DataGridDetailsSample()
{
InitializeComponent();
List<User> users = new List<User>
();
users.Add(new User() { Id = 1,
Name = "John Doe", Birthday = new DateTime(1971, 7, 23),
ImageUrl = "http://www.wpf-
tutorial.com/images/misc/john_doe.jpg" });
users.Add(new User() { Id = 2,
Name = "Jane Doe", Birthday = new DateTime(1974, 1, 17)
});
users.Add(new User() { Id = 3,
Name = "Sammy Doe", Birthday = new DateTime(1991, 9, 2)
});
dgUsers.ItemsSource = users;
}
}
Summary
Being able to show details for a DataGrid row is extremely useful, and with
the WPF DataGrid it's both easy and highly customizable, as you can see
from
the examples provided in this tutorial.
Previous Next
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
Introduction to WPF styles
Download this entire
tutorial as PDF right
now!
If you come from the world of developing for the web, using HTML and CSS, About WPF
you'll quickly realize that XAML is much like HTML: Using tags, you define a
What is WPF?
structural layout of your application. You can even make your elements look
WPF vs. WinForms
a certain way, using inline properties like Foreground, FontSize and so on,
just like you can locally style your HTML tags.
But what happens when you want to use the exact same font size and color Getting started
on three different TextBlock controls? You can copy/paste the desired Visual Studio Express
properties
to each of them, but what happens when three controls becomes Hello, WPF!
50 controls, spread out over several windows? And what happens when you
realize that the font
size should be 14 instead of 12?
XAML
WPF introduces styling, which is to XAML what CSS is to HTML. Using
styles, you can group a set of properties and assign them to specific controls What is XAML?
or all
controls of a specific type, and just like in CSS, a style can inherit from Basic XAML
another style. Events in XAML
Basic style example
A WPF application
We'll talk much more about all the details, but for this introduction chapter, I
want to show you a very basic example on how to use styling: Introduction
The Window
Working with App.xaml
<Window
Command-line parameters
x:Class="WpfTutorialSamples.Styles.SimpleStyleSample"
Resources
Handling exceptions
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Basic controls
Title="SimpleStyleSample" Height="200" The TextBlock control
Width="250"> The TextBlock control - Inline
<StackPanel Margin="10"> formatting
<StackPanel.Resources> The Label control
<Style TargetType="TextBlock"> The TextBox control
<Setter Property="Foreground" Value="Gray" The CheckBox control
Data binding
Introduction
Hello, bound world!
For the resources of my StackPanel, I define a Style. I use the TargetType Using the DataContext
property to tell WPF that this style should be applied towards
ALL TextBlock The UpdateSourceTrigger
controls within the scope (the StackPanel), and then I add two Setter property
elements to the style. The Setter elements are used to set specific
properties Responding to changes
for the target controls, in this case Foreground and FontSize properties. Value conversion with
The Property
property tells WPF which property we want to target, and the IValueConverter
Value property defines the desired value. The StringFormat property
Debugging data bindings
Notice that the last TextBlock is blue instead of gray. I did that to show you
that while a control might get styling from a designated style, you are
completely free to override this locally on the control - values defined directly
Commands
on the control will always take precedence over style values.
Introduction
Summary Using commands
Implementing custom
WPF styles make it very easy to create a specific look and then use it for commands
several controls, and while this first example was very local, I will show you
how to create global styles in the next chapters.
Common interface
Previous Next controls
The Menu control
The ContextMenu
The ToolBar control
comments powered by Disqus The StatusBar control
The Ribbon Control
Introduction
The
FlowDocumentScrollViewer
control
The
FlowDocumentPageViewer
control
The FlowDocumentReader
control
Creating a FlowDocument
from Code-behind
Advanced FlowDocument
content
The RichTextBox control
Misc. controls
The Border control
The Slider control
The ProgressBar control
The WebBrowser control
The WindowsFormsHost
control
The TabControl
Using the TabControl
Tab positions
Styling the TabItems
List controls
The ItemsControl
The ListBox control
The ComboBox control
ListView filtering
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
Using WPF styles
Download this entire
tutorial as PDF right
now!
In the previous chapter, where we introduced the concept of styles, we used About WPF
a very basic example of a locally defined style, which targeted a specific type
What is WPF?
of controls - the TextBlock. However, styles can be defined in several
WPF vs. WinForms
different scopes, depending on where and how you want to use them, and
you can even
restrict styles to only be used on controls where you explicitly
want it. In this chapter, I'll show you all the different ways in which a style can
be
defined. Getting started
Visual Studio Express
Local control specific style Hello, WPF!
You can actually define a style directly on a control, like this:
XAML
<Window
What is XAML?
x:Class="WpfTutorialSamples.Styles.ControlSpecificStyleSampl
Basic XAML
Events in XAML
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
A WPF application
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Introduction
Title="ControlSpecificStyleSample" Height="100" The Window
Width="300"> Working with App.xaml
<Grid Margin="10"> Command-line parameters
<TextBlock Text="Style test"> Resources
<TextBlock.Style> Handling exceptions
<Style>
<Setter Property="TextBlock.FontSize"
Value="36" /> Basic controls
</Style>
The TextBlock control
</TextBlock.Style>
The TextBlock control - Inline
</TextBlock>
formatting
</Grid>
The Label control
</Window>
The TextBox control
The CheckBox control
Panels
Introduction to WPF Panels
The Canvas
In this example, the style only affects this specific TextBlock control, so why The WrapPanel
bother? Well, in this case, it makes no sense at all. I could have replaced
all The StackPanel
that extra markup with a single FontSize property on the TextBlock control, The DockPanel
but as we'll see later, styles can do a bit more than just set properties,
for The Grid
instance, style triggers could make the above example useful in a real life The Grid - Rows & Columns
application. However, most of the styles you'll define will likely be in a
higher The Grid - Units
scope. The Grid - Spanning
The Grid - GridSplitter
Local child control style Using the Grid: A contact
form
Using the Resources section of a control, you can target child controls of this
control (and child controls of those child controls and so
on). This is basically
what we did in the introduction example in the last chapter, which looked like
Data binding
this:
Introduction
Hello, bound world!
<Window
Using the DataContext
x:Class="WpfTutorialSamples.Styles.SimpleStyleSample"
The UpdateSourceTrigger
property
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
Responding to changes
Value conversion with
IValueConverter
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
The StringFormat property
Title="SimpleStyleSample" Height="200"
Debugging data bindings
Width="250">
<StackPanel Margin="10">
<StackPanel.Resources>
<Style TargetType="TextBlock"> Commands
<Setter Property="Foreground" Value="Gray" Introduction
/> Using commands
<Setter Property="FontSize" Value="24" /> Implementing custom
</Style> commands
</StackPanel.Resources>
<TextBlock>Header 1</TextBlock>
<TextBlock>Header 2</TextBlock> Common interface
<TextBlock Foreground="Blue">Header 3</TextBlock> controls
</StackPanel>
The Menu control
</Window>
The ContextMenu
The ToolBar control
The StatusBar control
The Ribbon Control
Introduction
The
FlowDocumentScrollViewer
control
The
FlowDocumentPageViewer
control
This is great for the more local styling needs. For instance, it would make
The FlowDocumentReader
perfect sense to do this in a dialog where you simply needed a set of controls
control
to look the same, instead of setting the individual properties on each of them.
Creating a FlowDocument
from Code-behind
Window-wide styles Advanced FlowDocument
The next step up in the scope hierarchy is to define the style(s) within the content
Window resources. This is done in exactly the same way as above for the The RichTextBox control
StackPanel, but it's useful in those situations where you want a specific style
to apply to all controls within a window (or a UserControl for that matter)
and
not just locally within a specific control. Here's a modified example: Misc. controls
The Border control
<Window The Slider control
x:Class="WpfTutorialSamples.Styles.WindowWideStyleSample" The ProgressBar control
The WebBrowser control
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta The WindowsFormsHost
control
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WindowWideStyleSample" Height="200" The TabControl
Width="300">
Using the TabControl
<Window.Resources>
Tab positions
<Style TargetType="TextBlock">
Styling the TabItems
<Setter Property="Foreground" Value="Gray" />
<Setter Property="FontSize" Value="24" />
</Style>
List controls
</Window.Resources>
<StackPanel Margin="10"> The ItemsControl
<TextBlock>Header 1</TextBlock> The ListBox control
<TextBlock>Header 2</TextBlock> The ComboBox control
<TextBlock Foreground="Blue">Header 3</TextBlock>
</StackPanel>
</Window> The ListView control
Introduction
A simple ListView
ListView, data binding and
ItemTemplate
ListView with a GridView
How-to: Left aligned column
names
ListView grouping
ListView sorting
How-to: ListView with
column sorting
ListView filtering
As you can see, the result is exactly the same, but it does mean that you
could have controls placed everywhere within the window and the style would The TreeView control
still
apply. Introduction
A simple TreeView
Application-wide styles TreeView, data binding and
multiple templates
If you want your styles to be used all over the application, across different
Handling
windows, you can define it for the entire application. This is done in the
Selection/Expansion state
App.xaml file that Visual Studio has likely created for you, and it's done just
Lazy loading TreeView items
like in the window-wide example:
App.xaml
The DataGrid control
<Application x:Class="WpfTutorialSamples.App" Introduction
Custom columns
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta Details row
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Styles
StartupUri="Styles/WindowWideStyleSample.xaml">
Introduction
<Application.Resources>
Using styles
<Style TargetType="TextBlock">
Triggers
<Setter Property="Foreground" Value="Gray" />
Multi triggers
<Setter Property="FontSize" Value="24" />
Trigger animations
</Style>
</Application.Resources>
</Application>
Misc.
The DispatcherTimer
Window
<StackPanel Margin="10">
<TextBlock>Header 1</TextBlock>
<TextBlock>Header 2</TextBlock>
<TextBlock Foreground="Blue">Header 3</TextBlock>
</StackPanel>
</Window>
Explicitly using styles
You have a lot of control over how and where to apply styling to your
controls, from local styles and right up to the application-wide styles, that can
help you get a consistent look all over your application, but so far, all of our
styles have targeted a specific control type, and then ALL of these
controls
have used it. This doesn't have to be the case though.
By setting the x:Key property on a style, you are telling WPF that you only
want to use this style when you explicitly reference it on a
specific control.
Let's try an example where this is the case:
<Window
x:Class="WpfTutorialSamples.Styles.ExplicitStyleSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ExplicitStyleSample" Height="150"
Width="300">
<Window.Resources>
<Style x:Key="HeaderStyle" TargetType="TextBlock">
<Setter Property="Foreground" Value="Gray" />
<Setter Property="FontSize" Value="24" />
</Style>
</Window.Resources>
<StackPanel Margin="10">
<TextBlock>Header 1</TextBlock>
<TextBlock Style="{StaticResource
HeaderStyle}">Header 2</TextBlock>
<TextBlock>Header 3</TextBlock>
</StackPanel>
</Window>
Notice how even though the TargetType is set to TextBlock, and the style is
defined for the entire window, only the TextBlock in the middle, where I
explicitly reference the HeaderStyle style, uses the style. This allows you to
define styles that target a specific control type, but only
use it in the places
where you need it.
Summary
WPF styling allows you to easily re-use a certain look for your controls all
over the application. Using the x:Key property, you can decide whether a
style
should be explicitly referenced to take effect, or if it should target all
controls no matter what.
Previous Next
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
Trigger, DataTrigger & EventTrigger
Download this entire
tutorial as PDF right
now!
So far, we worked with styles by setting a static value for a specific property. About WPF
However, using triggers, you can change the value of a given property,
once
What is WPF?
a certain condition changes. Triggers come in multiple flavors: Property
WPF vs. WinForms
triggers, event triggers and data triggers. They allow you to do stuff that
would normally be done in code-behind completely in markup instead, which
is all a part of the ongoing process of separating style and code.
Getting started
Property trigger Visual Studio Express
Hello, WPF!
The most common trigger is the property trigger, which in markup is simply
defined with a <Trigger> element. It watches a specific property on the
owner
control and when that property has a value that matches the specified value,
XAML
properties can change. In theory this might sound a bit complicated, but
it's
actually quite simple once we turn theory into an example: What is XAML?
Basic XAML
Events in XAML
<Window
x:Class="WpfTutorialSamples.Styles.StyleTriggersSample"
In this style, we set the Foreground property to blue, to make it look like a Data binding
hyperlink. We then add a trigger, which listens to theIsMouseOver property - Introduction
once this property changes to True, we apply two setters: We change the Hello, bound world!
Foreground to red and then we make it underlined. This is a great example Using the DataContext
on how easy it is to use triggers to apply design changes,
completely without The UpdateSourceTrigger
any code-behind code. property
Responding to changes
We define a local style for this specific TextBlock, but as shown in the Value conversion with
previous articles, the style could have been globally defined as well, if we IValueConverter
wanted it to apply to all TextBlock controls in the application. The StringFormat property
Debugging data bindings
Data triggers
Data triggers, represented by the <DataTrigger> element, are used for
properties that are not necessarily dependency properties. They work by Commands
creating a binding to a regular property, which is then monitored for changes. Introduction
This also opens up for binding your trigger to a property on a different
control. Using commands
For instance, consider the following example: Implementing custom
commands
<Window
x:Class="WpfTutorialSamples.Styles.StyleDataTriggerSample"
Common interface
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta controls
The Menu control
The ContextMenu
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
The ToolBar control
Title="StyleDataTriggerSample" Height="200"
The StatusBar control
Width="200">
The Ribbon Control
<StackPanel HorizontalAlignment="Center"
VerticalAlignment="Center">
<CheckBox Name="cbSample" Content="Hello, world?"
Rich Text controls
/>
The TabControl
Using the TabControl
Tab positions
Styling the TabItems
List controls
The ItemsControl
The ListBox control
In this example, we have a CheckBox and a TextBlock. Using a
The ComboBox control
DataTrigger, we bind the TextBlock to the IsChecked property of the
CheckBox. We then supply a default style, where the text is "No" and the
foreground color is red, and then,
using a DataTrigger, we supply a style for
when the IsChecked property of the CheckBox is changed to True, in which
The ListView control
case we make it green with a text
saying "Yes!" (as seen on the screenshot). Introduction
A simple ListView
Event triggers ListView, data binding and
ItemTemplate
Event triggers, represented by the <EventTrigger> element, are mostly used ListView with a GridView
to trigger an animation, in response to an event being called. We haven't How-to: Left aligned column
discussed animations yet, but to demonstrate how an event trigger works, names
we'll use them anyway. Have a look on the chapter about animations for ListView grouping
more
details. Here's the example: ListView sorting
How-to: ListView with
<Window column sorting
The markup might look a bit overwhelming, but if you run this sample and
look at the result, you'll see that we've actually accomplished a pretty cool
animation, going both ways, in ~20 lines of XAML. As you can see, I use an
EventTrigger to subscribe to two events: MouseEnter and MouseLeave.
When the mouse enters, I make a smooth and animated transition to a
FontSize of 28 pixels in 300 milliseconds. When the mouse
leaves, I change
the FontSize back to 18 pixels but I do it a bit slower, just because it looks
kind of cool.
Summary
WPF styles make it easy to get a consistent look, and with triggers, this look
becomes dynamic. Styles are great in your application, but they're even
better when used in control templates etc. You can read more about that
elsewhere in this tutorial.
In the next article, we'll look at multi triggers, which allow us to apply styles
based on multiple properties.
Previous Next
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
WPF MultiTrigger and
MultiDataTrigger Download this entire
tutorial as PDF right
now!
About WPF
In the previous chapter, we worked with triggers to get dynamic styles. So far
What is WPF?
they have all been based on a single property, but WPF also supports multi
WPF vs. WinForms
triggers, which can monitor two or more property conditions and only trigger
once all of them are satisfied.
There are two types of multi triggers: The MultiTrigger, which just like the Getting started
regular Trigger works on dependency properties, and then the Visual Studio Express
MultiDataTrigger, which works by binding to any kind of property. Let's start Hello, WPF!
with a quick example on how to use the MultiTrigger.
MultiTrigger XAML
What is XAML?
<Window
Basic XAML
x:Class="WpfTutorialSamples.Styles.StyleMultiTriggerSample"
Events in XAML
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
A WPF application
Introduction
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" The Window
Title="StyleMultiTriggerSample" Height="100" Working with App.xaml
Width="250"> Command-line parameters
<Grid> Resources
<TextBox VerticalAlignment="Center" Handling exceptions
HorizontalAlignment="Center" Text="Hover and focus here"
Width="150">
<TextBox.Style> Basic controls
<Style TargetType="TextBox">
The TextBlock control
<Style.Triggers>
The TextBlock control - Inline
<MultiTrigger>
formatting
<MultiTrigger.Conditions>
The Label control
<Condition
The TextBox control
Property="IsKeyboardFocused" Value="True" />
The CheckBox control
<Condition
Data binding
Introduction
In this example, we use a trigger to change the background color of the Hello, bound world!
TextBox once it has keyboard focus AND the mouse cursor is over it, as Using the DataContext
seen on the
screenshot. This trigger has two conditions, but we could easily The UpdateSourceTrigger
have added more if needed. In the Setters section, we define the properties property
we wish to
change when all the conditions are met - in this case, just the one Responding to changes
(background color). Value conversion with
IValueConverter
MultiDataTrigger The StringFormat property
Debugging data bindings
Just like a regular DataTrigger, the MultiDataTrigger is cool because it uses
bindings to monitor a property. This means that you can use all of the cool
WPF binding techniques, including binding to the property of another control
etc. Let me show you how easy it is:
Commands
Introduction
<Window Using commands
x:Class="WpfTutorialSamples.Styles.StyleMultiDataTriggerSamp Implementing custom
commands
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
Common interface
controls
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" The Menu control
Title="StyleMultiDataTriggerSample" Height="150" The ContextMenu
Width="200"> The ToolBar control
<StackPanel HorizontalAlignment="Center" The StatusBar control
VerticalAlignment="Center"> The Ribbon Control
<CheckBox Name="cbSampleYes" Content="Yes" />
<CheckBox Name="cbSampleSure" Content="I'm sure"
/> Rich Text controls
<TextBlock HorizontalAlignment="Center"
Introduction
Margin="0,20,0,0" FontSize="28">
The
<TextBlock.Style>
FlowDocumentScrollViewer
<Style TargetType="TextBlock">
control
<Setter Property="Text"
The
Value="Unverified" />
FlowDocumentPageViewer
<Setter Property="Foreground"
control
Value="Red" />
The FlowDocumentReader
<Style.Triggers>
control
<MultiDataTrigger>
Creating a FlowDocument
<MultiDataTrigger.Conditions>
from Code-behind
<Condition Binding="
Advanced FlowDocument
{Binding ElementName=cbSampleYes, Path=IsChecked}"
content
Value="True" />
The RichTextBox control
<Condition Binding="
{Binding ElementName=cbSampleSure, Path=IsChecked}"
Value="True" />
</MultiDataTrigger.Conditions> Misc. controls
<Setter Property="Text" The Border control
Value="Verified" /> The Slider control
<Setter Property="Foreground" The ProgressBar control
Value="Green" /> The WebBrowser control
</MultiDataTrigger> The WindowsFormsHost
</Style.Triggers> control
</Style>
</TextBlock.Style>
</TextBlock> The TabControl
</StackPanel>
Using the TabControl
</Window>
Tab positions
Styling the TabItems
List controls
The ItemsControl
The ListBox control
The ComboBox control
ListView filtering
Previous Next
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
Trigger animations
Download this entire
tutorial as PDF right
now!
One of the things that became a LOT easier with WPF, compared to previous About WPF
frameworks like WinForms, is animation. Triggers have direct support for
What is WPF?
using
animations in response to the trigger being fired, instead of just
WPF vs. WinForms
switching between two static values.
For this, we use the EnterActions and ExitActions
properties, which are
present in all of the trigger types already discussed (except for the Getting started
EventTrigger), both single and multiple. Here's an example: Visual Studio Express
Hello, WPF!
<Window
x:Class="WpfTutorialSamples.Styles.StyleTriggerEnterExitActi
XAML
What is XAML?
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
Basic XAML
Events in XAML
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="StyleTriggerEnterExitActions" Height="200"
A WPF application
Width="200" UseLayoutRounding="True">
<Grid> Introduction
<Border Background="LightGreen" Width="100" The Window
Height="100" BorderBrush="Green"> Working with App.xaml
<Border.Style> Command-line parameters
<Style TargetType="Border"> Resources
<Style.Triggers> Handling exceptions
<Trigger Property="IsMouseOver"
Value="True">
<Trigger.EnterActions> Basic controls
<BeginStoryboard> The TextBlock control
<Storyboard> The TextBlock control - Inline
formatting
<ThicknessAnimation Duration="0:0:0.400" To="3" The Label control
Storyboard.TargetProperty="BorderThickness" /> The TextBox control
<DoubleAnimation The CheckBox control
Duration="0:0:0.300" To="125"
Commands
Introduction
Using commands
Implementing custom
commands
Common interface
controls
The Menu control
In this example, we have a green square. It has a trigger that fires once the The ContextMenu
mouse is over, in which case it fires of several animations, all defined in
the The ToolBar control
EnterActions part of the trigger. In there, we animate the thickness of the The StatusBar control
border from its default 0 to a thickness of 3, and then we
animate the width The Ribbon Control
and height from 100 to 125. This all happens simultaneously, because they
are a part of the same StoryBoard, and even at
slightly different speeds,
since we have full control of how long each animation should run. Rich Text controls
Introduction
We use the ExitActions to reverse the changes we made, with animations
The
that goes back to the default values. We run the reversing animations slightly
FlowDocumentScrollViewer
faster, because we can and because it looks cool.
control
The two states are represented on the two screenshots, but to fully The
appreciate the effect, you should try running the example on your own FlowDocumentPageViewer
machine, using
the source code above. control
The FlowDocumentReader
Summary control
Creating a FlowDocument
Using animations with style triggers is very easy, and while we haven't fully from Code-behind
explored all you can do with WPF animations yet, the example used above Advanced FlowDocument
should give you an idea on just how flexible both animations and styles are. content
The RichTextBox control
Previous Next
Misc. controls
The Border control
comments powered by Disqus The Slider control
The ProgressBar control
The WebBrowser control
The WindowsFormsHost
control
The TabControl
Using the TabControl
Tab positions
Styling the TabItems
List controls
The ItemsControl
The ListBox control
The ComboBox control
ListView filtering
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
The DispatcherTimer
Download this entire
tutorial as PDF right
now!
In WinForms, there's a control called the Timer, which can perform an action About WPF
repeatedly within a given interval. WPF has this possibility as well, but
What is WPF?
instead of an invisible control, we have the DispatcherTimer control. It does
WPF vs. WinForms
pretty much the same thing, but instead of dropping it on
your form, you
create and use it exclusively from your Code-behind code.
The DispatcherTimer class works by specifying an interval and then Getting started
subscribing to the Tick event that will occur each time this interval
is met. Visual Studio Express
The DispatcherTimer is not started before you call the Start() method or set Hello, WPF!
the IsEnabled property to true.
Let's try a simple example where we use a DispatcherTimer to create a
XAML
digital clock:
What is XAML?
Basic XAML
<Window
Events in XAML
x:Class="WpfTutorialSamples.Misc.DispatcherTimerSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
A WPF application
Introduction
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" The Window
Title="DispatcherTimerSample" Height="150" Working with App.xaml
Width="250"> Command-line parameters
<Grid> Resources
<Label Name="lblTime" FontSize="48" Handling exceptions
HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</Window> Basic controls
The TextBlock control
The TextBlock control - Inline
using System; formatting
using System.Windows; The Label control
using System.Windows.Threading; The TextBox control
The CheckBox control
Commands
The XAML part is extremely simple - it's merely a centered label with a large Introduction
font size, used to display the current time. Using commands
Implementing custom
Code-behind is where the magic happens in this example. In the constructor commands
of the window, we create a DispatcherTimer instance. We set the Interval
property to one second, subscribe to the Tick event and then we start the
timer. In the Tick event, we simply update the label to
show the current time.
Common interface
Of course, the DispatcherTimer can work at smaller or much bigger intervals. controls
For instance, you might only want something to happen every 30 seconds or The Menu control
5
minutes - just use the TimeSpan.From* methods, like FromSeconds or The ContextMenu
FromMinutes, or create a new TimeSpan instance that completely fits your The ToolBar control
needs. The StatusBar control
The Ribbon Control
To show what the DispatcherTimer is capable of, let's try updating more
frequently... A lot more frequently!
Rich Text controls
using System;
Introduction
using System.Windows;
The
using System.Windows.Threading;
FlowDocumentScrollViewer
control
namespace WpfTutorialSamples.Misc
The
{
FlowDocumentPageViewer
public partial class DispatcherTimerSample :
control
Window
The FlowDocumentReader
{
control
public DispatcherTimerSample()
Creating a FlowDocument
{
from Code-behind
InitializeComponent();
Advanced FlowDocument
DispatcherTimer timer = new
content
DispatcherTimer();
The RichTextBox control
timer.Interval =
TimeSpan.FromMilliseconds(1);
timer.Tick += timer_Tick;
Misc. controls
timer.Start();
} The Border control
The Slider control
void timer_Tick(object sender, EventArgs The ProgressBar control
e) The WebBrowser control
{ The WindowsFormsHost
lblTime.Content = control
DateTime.Now.ToString("HH:mm:ss.fff");
}
} The TabControl
} Using the TabControl
Tab positions
Styling the TabItems
List controls
The ItemsControl
The ListBox control
The ComboBox control
As you can see, we now ask the DispatcherTimer to fire every millisecond! In
the Tick event, we use a custom time format string to show the milliseconds The ListView control
in
the label as well. Now you have something that could easily be used as a Introduction
stopwatch - just add a couple of buttons to the Window and then have them A simple ListView
call the Stop(), Start() and Restart() methods on the timer. ListView, data binding and
ItemTemplate
Summary ListView with a GridView
How-to: Left aligned column
There are many situations where you would need something in your
names
application to occur at a given interval, and using the DispatcherTimer, it's
ListView grouping
quite easy
to accomplish. Just be aware that if you do something complicated
ListView sorting
in your Tick event, it shouldn't run too often, like in the last example where
How-to: ListView with
the timer
ticks each millisecond - that will put a heavy strain on the computer
column sorting
running your application.
ListView filtering
Also be aware that the DispatcherTimer is not 100% precise in all situations.
The tick operations are placed on the Dispatcher queue, so if the computer is
under a lot of pressure, your operation might be delayed. The .NET The TreeView control
framework promises that the Tick event will never occur too early, but can't Introduction
promise
that it won't be slightly delayed. However, for most use cases, the A simple TreeView
DispatcherTimer is more than precise enough. TreeView, data binding and
multiple templates
If you need your timer to have a higher priority in the queue, you can set the Handling
DispatcherPriority by sending one of the values along on the Selection/Expansion state
DispatcherTimer
priority. More information about it can be found on this Lazy loading TreeView items
MSDN article.
Styles
Introduction
Using styles
Triggers
Multi triggers
Trigger animations
Misc.
The DispatcherTimer
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
Playing audio
Download this entire
tutorial as PDF right
now!
WPF comes with excellent built-in audio and video support, as you'll see in About WPF
the next couple of chapters of this tutorial. In this particular article, we'll
be
What is WPF?
discussing the ability to play audio, coming from actual audio files, e.g. in the
WPF vs. WinForms
MP3 format, but first, let's have a look at couple of simpler
approaches.
System sounds and the SoundPlayer
Getting started
WPF has a class called SoundPlayer, which will play audio content based
Visual Studio Express
on the WAV format for you. WAV is not a very widely used format
today,
Hello, WPF!
mainly because it's uncompressed and therefore takes up a LOT of space.
So while the SoundPlayer class is simple to use, it's not terribly useful.
Instead, we'll be focusing on the MediaPlayer and MediaElement classes, XAML
which allows the playback of MP3 files, but first, let's have a look at the What is XAML?
simplest way of playing a sound in your
WPF application - the SystemSounds Basic XAML
class. Events in XAML
The SystemSounds class offers several different sounds, which corresponds
to the sound defined for this event by the user in Windows, like Exclamation
A WPF application
and
Question. You can piggyback on these sounds and settings and play
them with a single line of code: Introduction
The Window
Working with App.xaml
SystemSounds.Beep.Play();
Command-line parameters
Resources
Here's a complete example, where we use all of the currently available Handling exceptions
sounds:
RoutedEventArgs e) Introduction
{ The
SystemSounds.Hand.Play(); FlowDocumentScrollViewer
} control
The
private void btnQuestion_Click(object FlowDocumentPageViewer
sender, RoutedEventArgs e) control
{ The FlowDocumentReader
SystemSounds.Question.Play(); control
} Creating a FlowDocument
} from Code-behind
} Advanced FlowDocument
content
The RichTextBox control
Misc. controls
The Border control
The Slider control
The ProgressBar control
The WebBrowser control
The WindowsFormsHost
control
There are of course several limitations to using this approach. First of all, you
only get access to these five sounds, and second of all, the user may
have The TabControl
disabled them in Windows, in which case the expected sound will be Using the TabControl
replaced with silence. On the other hand, if you only want to use these Tab positions
sounds the
same way that Windows does, it makes it extremely easy to Styling the TabItems
produce a sound for warnings, questions etc. In that case, it's a good thing
that your
application will respect the user's choice of silence.
List controls
The MediaPlayer class
The ItemsControl
The MediaPlayer class uses Windows Media Player technology to play both The ListBox control
audio and video in several modern formats, e.g. MP3 and MPEG. In this The ComboBox control
article,
we'll be using it for playing just audio, and then focus on video in the
next article.
The ListView control
Playing an MP3 file with the MediaPlayer class is very simple, as we'll see in
Introduction
this next example:
A simple ListView
ListView, data binding and
<Window ItemTemplate
x:Class="WpfTutorialSamples.Audio_and_Video.MediaPlayerAudio
ListView with a GridView
How-to: Left aligned column
names
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
ListView grouping
ListView sorting
How-to: ListView with
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
column sorting
Title="MediaPlayerAudioSample" Height="100"
ListView filtering
Width="200">
<Grid VerticalAlignment="Center"
HorizontalAlignment="Center">
The TreeView control
<Button Name="btnOpenAudioFile"
Click="btnOpenAudioFile_Click">Open Audio file</Button> Introduction
</Grid> A simple TreeView
</Window> TreeView, data binding and
multiple templates
Handling
Selection/Expansion state
using System; Lazy loading TreeView items
using System.Windows;
using System.Windows.Media;
using Microsoft.Win32; The DataGrid control
Introduction
namespace WpfTutorialSamples.Audio_and_Video
Custom columns
{
Details row
public partial class MediaPlayerAudioSample :
Window
{
private MediaPlayer mediaPlayer = new Styles
MediaPlayer(); Introduction
Using styles
public MediaPlayerAudioSample() Triggers
{ Multi triggers
InitializeComponent(); Trigger animations
}
In this example, we just have a single button, which will show an
OpenFileDialog and let you select an MP3 file. Once that is done, it will use
the already
created MediaPlayer instance to open and play this file. Notice
that the MediaPlayer object is created outside of the event handler. This
makes sure that
the object is not prematurely garbage collected because it
goes out of scope once the event handler is done, which would result in the
playback stopping.
Please also notice that no exception handling is done for this example, as
usual to keep the example as compact as possible, but in this case also
because
the Open() and Play() methods actually doesn't throw any
exceptions. Instead, you can use the MediaOpened and MediaFailed events
to act when things go
right or wrong.
Controlling the MediaPlayer
In our first MediaPlayer example, we just opened and automatically started
playing a file, without giving the user a chance to control the playback
process, but obviously, the MediaPlayer control offers you full control of
playback. Here's an example showing you the most important functions:
<Window
x:Class="WpfTutorialSamples.Audio_and_Video.MediaPlayerAudio
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MediaPlayerAudioControlSample" Height="120"
Width="300">
<StackPanel Margin="10">
<Label Name="lblStatus" Content="Not playing..."
HorizontalContentAlignment="Center" Margin="5" />
<WrapPanel HorizontalAlignment="Center">
<Button Name="btnPlay"
Click="btnPlay_Click">Play</Button>
<Button Name="btnPause" Margin="5,0"
Click="btnPause_Click">Pause</Button>
<Button Name="btnStop"
Click="btnStop_Click">Stop</Button>
</WrapPanel>
</StackPanel>
</Window>
using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Threading;
using Microsoft.Win32;
namespace WpfTutorialSamples.Audio_and_Video
{
public partial class MediaPlayerAudioControlSample
: Window
{
private MediaPlayer mediaPlayer = new
MediaPlayer();
public MediaPlayerAudioControlSample()
{
InitializeComponent();
OpenFileDialog openFileDialog =
new OpenFileDialog();
openFileDialog.Filter = "MP3 files
(*.mp3)|*.mp3|All files (*.*)|*.*";
if(openFileDialog.ShowDialog() ==
true)
mediaPlayer.Open(new
Uri(openFileDialog.FileName));
{
mediaPlayer.Play();
}
In this example, we have expanded our player a bit, so that it now contains a
Play, Pause and Stop button, as well as a label for showing the current
playback status. The MP3 file to be played is loaded the same way, but we
do it as soon as the application starts, to keep the example simple.
Right after the MP3 is loaded, we start a timer, which ticks every second. We
use this event to update the status label, which will show the current
progress
as well as the entire length of the loaded file.
The three buttons each simply call a corresponding method on the
MediaPlayer object - Play, Pause and Stop.
Summary
There are several more options that you can let your user control, but I want
to save that for when we have talked about the video aspects of the
MediaPlayer class - at that point, I'll do a more complete example of a media
player capable of playing both audio and video files, with more options.
Previous Next
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
Playing video
Download this entire
tutorial as PDF right
now!
In the previous article, we used the MediaPlayer class to play an MP3 file, About WPF
but the cool part about the MediaPlayer class is that it can
work with video
What is WPF?
files as well. However, since a video actually needs to be displayed
WPF vs. WinForms
somewhere in the interface, as opposed to an audio file, we need a
wrapper
element to visually represent the MediaPlayer instance. This is where the
MediaElement comes into play.
Getting started
The MediaElement Visual Studio Express
Hello, WPF!
The MediaElement acts as a wrapper around MediaPlayer, so that you can
display video content at a given place in your application, and because of
that, it
can play both audio and video files, although the visual representation
XAML
doesn't really matter in dealing with audio files.
What is XAML?
I want to show you just how easy you can show video content in your WPF Basic XAML
application, so here's a bare minimum example: Events in XAML
<Window
x:Class="WpfTutorialSamples.Audio_and_Video.MediaPlayerVideo A WPF application
Introduction
The Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta Working with App.xaml
Command-line parameters
Resources
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Handling exceptions
Title="MediaPlayerVideoSample" Height="300"
Width="300">
<Grid>
Basic controls
<MediaElement
Source="http://hubblesource.stsci.edu/sources/video/clips/de The TextBlock control
/> The TextBlock control - Inline
</Grid> formatting
</Window> The Label control
The TextBox control
The CheckBox control
Panels
Introduction to WPF Panels
The Canvas
The WrapPanel
The StackPanel
The DockPanel
The Grid
The Grid - Rows & Columns
The Grid - Units
The Grid - Spanning
The Grid - GridSplitter
Using the Grid: A contact
form
And that's it - a single line of XAML inside your window and you're displaying
video (this specific video is about the Hubble Space Telescope - more
information can be found at this website) in your WPF application.
Data binding
Dealing with video size Introduction
Hello, bound world!
Our examples in this article so far has just used the same size for the Using the DataContext
MediaElement, not taking the dimensions of the video into consideration. The UpdateSourceTrigger
This is
possible because the MediaElement can stretch/shrink the content to property
fit the available width/height and will do so by default. This is caused by the Responding to changes
Stretch property, which is set to Uniform by default, meaning that the video Value conversion with
will be stretched, while respecting the
aspect ratio. IValueConverter
The StringFormat property
If your window is larger than your video, this might work just fine, but perhaps
Debugging data bindings
you don't want any stretching to occur? Or perhaps you want the window to
adjust to fit your video's dimensions, instead of the other way around?
The first thing you need to do is to turn off stretching by setting the Stretch Commands
property to None. This will ensure that
the video is rendered in its natural Introduction
size. Now if you want the window to adjust to that, it's actually quite simple - Using commands
just use the ResizeToContent property on the Window to accomplish this. Implementing custom
Here's a full example: commands
<Window
x:Class="WpfTutorialSamples.Audio_and_Video.MediaPlayerVideo Common interface
controls
The Menu control
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta The ContextMenu
The ToolBar control
The StatusBar control
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" The Ribbon Control
Title="MediaPlayerVideoSizeSample" Height="500"
Width="500" SizeToContent="WidthAndHeight">
<Grid>
Rich Text controls
<MediaElement
Introduction
Source="http://hubblesource.stsci.edu/sources/video/clips/de
The
Name="mePlayer" Stretch="None" />
FlowDocumentScrollViewer
</Grid>
control
</Window>
The
FlowDocumentPageViewer
control
The FlowDocumentReader
control
Creating a FlowDocument
from Code-behind
Advanced FlowDocument
content
The RichTextBox control
Misc. controls
The Border control
The Slider control
The ProgressBar control
The WebBrowser control
The WindowsFormsHost
As you can see, despite the initial values of 500 for the Width and Height
control
properties on the Window, the size is adjusted (down, in this case) to match
the
resolution of the video.
Please notice that this might cause the window to have a size of zero (only The TabControl
the title bar and borders will be visible) during startup, while the video is Using the TabControl
loaded. To prevent this, you can set the MinWidth and MinHeight properties Tab positions
on the Window to something that suits your needs. Styling the TabItems
Controlling the MediaElement/MediaPlayer
As you can see if you run our previous examples, the video starts playing as
List controls
soon as the player has buffered enough data, but you can change this The ItemsControl
behavior
by using the LoadedBehavior property. We'll do that in the next The ListBox control
example, where we'll also add a couple of buttons to control the playback: The ComboBox control
<Window
x:Class="WpfTutorialSamples.Audio_and_Video.MediaPlayerVideo The ListView control
Introduction
A simple ListView
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta ListView, data binding and
ItemTemplate
ListView with a GridView
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" How-to: Left aligned column
Title="MediaPlayerVideoControlSample" Height="300" names
Width="300"> ListView grouping
<Grid Margin="10"> ListView sorting
<Grid.RowDefinitions> How-to: ListView with
<RowDefinition Height="*" /> column sorting
lblStatus.Content
= String.Format("{0} / {1}",
mePlayer.Position.ToString(@"mm\:ss"),
mePlayer.NaturalDuration.TimeSpan.ToString(@"mm\:ss"));
}
else
lblStatus.Content = "No
file selected...";
}
This example is much like the one we did in the previous article for audio, just
for video in this case. We have a bottom area with a set of buttons for
controlling the playback, a label for showing the status, and then a
MediaElement control in the top area to show the actual video.
Upon application start, we create and start a timer, which ticks every second.
We use this event to update the status label, which will show the current
progress as well as the entire length of the loaded file, as seen on the
screenshot.
The three buttons each simply call a corresponding method on the
MediaElement control - Play(), Pause() and Stop().
Summary
Once again it's clear how easy WPF makes even advanced things like
playing a video. So far, we've worked with some basic examples, but in the
next chapter,
I'm going to combine all the stuff we've learned about audio and
video playback into a single, media player with a lot more functionality than
we've seen
so far. Read on!
Previous Next
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
How-to: Creating a complete
Audio/Video player Download this entire
tutorial as PDF right
now!
About WPF
As a conclusion to the last chapters on playing audio and video, I decided to
What is WPF?
create a more complete sample, where we take advantage of the fact that the
WPF vs. WinForms
MediaPlayer/MediaElement classes can handle both audio and video.
I will take the concepts used in the articles about playing audio and video and
combine them with several controls which we have already discussed Getting started
previously in this article, and turn it all into a WPF Media Player. The result Visual Studio Express
will look something like this: Hello, WPF!
XAML
What is XAML?
Basic XAML
Events in XAML
But that's just when it plays audio/MP3 files. Once a video is loaded, the
interface automatically expands to show the video content inside the window:
A WPF application
Introduction
The Window
Working with App.xaml
Command-line parameters
Resources
Handling exceptions
Basic controls
The TextBlock control
The TextBlock control - Inline
formatting
The Label control
The TextBox control
The CheckBox control
Also notice that we have set the MediaElement Stretch property to None, Data binding
and the Window SizeToContentMode
to WidthAndHeight. This is what
Introduction
keeps the window to the minimum size needed to show the interface as well
Hello, bound world!
as the video, if one is playing.
Using the DataContext
For showing the Volume, we've used a ProgressBar control in the lower, right The UpdateSourceTrigger
corner. This doesn't currently let the user control the volume, but merely property
reflects the Volume property on the MediaElement control, through a classic Responding to changes
data binding. We've implemented a small but neat trick for
letting the user Value conversion with
control the volume anyway though - more on that below. IValueConverter
The StringFormat property
The code Debugging data bindings
In Code-behind, we re-use several techniques already used in our previous
examples. For instance, we initiate a DispatcherTimer and let it tick every
Commands
second, to show the current playback progress in the interface. In the Tick
Introduction
event of the timer, we update Slider control, by settingMinimum, Maximum
Using commands
and current Value according to the file being played, and by hooking up to
Implementing custom
the ValueChanged event on the slider, we use that to update the label
commands
showing the current playback progress in hours, minutes and seconds.
The Slider control also allows the user to skip to another part of the file,
simply by dragging the "thumb" to another location. We handle this by Common interface
implementing events for DragStarted and DragCompleted - the first one to controls
set a variable ( userIsDraggingSlider) that tells the timer not to update the The Menu control
Slider while we drag, and the second one to skip to the designated part when The ContextMenu
the user releases the mouse button. The ToolBar control
The StatusBar control
There are CanExecute and Executed handlers for the four commands we
The Ribbon Control
use and especially the ones for Pause and Stop are interesting. Since
we
can't get a current state from the MediaElement control, we have to keep
track of the current state ourselves. This is done with a local variable called
mediaPlayerIsPlaying, which we regularly check to see if the Pause and
Rich Text controls
Stop buttons should be enabled. Introduction
The
The last little detail you should notice is the Grid_MouseWheel event. The FlowDocumentScrollViewer
main Grid covers the entire window, so by subscribing to this
event, we get control
notified when the user scrolls the wheel. When that happens, as a little The
gimmick, we turn the volume up or down, depending on the direction
(we get FlowDocumentPageViewer
that by looking at the Delta property, which is negative when scrolling down control
and positive when scrolling up). This is immediately reflected in the
user The FlowDocumentReader
interface, where a ProgressBar control is bound to the Volume property of control
the MediaElement. Creating a FlowDocument
from Code-behind
The complete source code Advanced FlowDocument
content
With all the theory behind the example described, here's the complete source
The RichTextBox control
code:
<Window
Misc. controls
x:Class="WpfTutorialSamples.Audio_and_Video.AudioVideoPlayer
The Border control
The Slider control
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta The ProgressBar control
The WebBrowser control
The WindowsFormsHost
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" control
Title="WPF Media Player" Height="300" Width="300"
MinWidth="300" SizeToContent="WidthAndHeight">
<Window.CommandBindings> The TabControl
<CommandBinding Command="ApplicationCommands.Open" Using the TabControl
CanExecute="Open_CanExecute" Executed="Open_Executed" /> Tab positions
<CommandBinding Command="MediaCommands.Play" Styling the TabItems
CanExecute="Play_CanExecute" Executed="Play_Executed" />
<CommandBinding Command="MediaCommands.Pause"
CanExecute="Pause_CanExecute" Executed="Pause_Executed" />
List controls
<CommandBinding Command="MediaCommands.Stop"
The ItemsControl
using System;
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Threading;
using Microsoft.Win32;
namespace WpfTutorialSamples.Audio_and_Video
{
public partial class
AudioVideoPlayerCompleteSample : Window
{
private bool mediaPlayerIsPlaying = false;
private bool userIsDraggingSlider = false;
public AudioVideoPlayerCompleteSample()
{
InitializeComponent();
(mePlayer.NaturalDuration.HasTimeSpan) &&
(!userIsDraggingSlider))
{
sliProgress.Minimum = 0;
sliProgress.Maximum =
mePlayer.NaturalDuration.TimeSpan.TotalSeconds;
sliProgress.Value =
mePlayer.Position.TotalSeconds;
}
}
private void
sliProgress_DragStarted(object sender,
DragStartedEventArgs e)
{
userIsDraggingSlider = true;
}
private void
sliProgress_DragCompleted(object sender,
DragCompletedEventArgs e)
{
userIsDraggingSlider = false;
mePlayer.Position =
TimeSpan.FromSeconds(sliProgress.Value);
}
private void
sliProgress_ValueChanged(object sender,
RoutedPropertyChangedEventArgs<double> e)
{
lblProgressStatus.Text =
TimeSpan.FromSeconds(sliProgress.Value).ToString(@"hh\:mm\:s
}
}
Summary
The code listing might look a bit overwhelming, but as you can see, there's a
lot of repetition in it. If you take that out of the picture, you will soon
realize
that creating a pretty capable media player in WPF is really not that hard!
Feel free to expand on this example for your own projects - how about
implementing a playlist feature?
Previous Next
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
Speech synthesis (making WPF talk)
Download this entire
tutorial as PDF right
now!
In the System.Speech assembly, Microsoft has added something really cool: About WPF
Speech Synthesis, the ability to transform text into spoken words, and
What is WPF?
Speech
Recognition, the ability to translate spoken words into text. We'll be
WPF vs. WinForms
focusing on the speech synthesis in this article, and then get into speech
recognition in the next one.
To transform text into spoken words, we'll be using the SpeechSynthesizer Getting started
class. This class resides in the System.Speech assembly, which
we'll need to Visual Studio Express
add to use it in our application. Depending on which version of Visual Studio Hello, WPF!
you use, the process looks something like this:
XAML
What is XAML?
Basic XAML
Events in XAML
A WPF application
Introduction
The Window
Working with App.xaml
Command-line parameters
Resources
Handling exceptions
Basic controls
The TextBlock control
The TextBlock control - Inline
formatting
The Label control
The TextBox control
The CheckBox control
Panels
Introduction to WPF Panels
With the appropriate assembly added, we can now use the
The Canvas
SpeechSynthesizer class from the System.Speech.Synthesis namespace.
The WrapPanel
With that in place, we'll kick
off with yet another very simple "Hello, world!"
The StackPanel
inspired example, this time in spoken words:
The DockPanel
The Grid
<Window The Grid - Rows & Columns
x:Class="WpfTutorialSamples.Audio_and_Video.SpeechSynthesisS The Grid - Units
The Grid - Spanning
The Grid - GridSplitter
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta Using the Grid: A contact
form
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="SpeechSynthesisSample" Height="150"
Data binding
Width="150">
Introduction
<Grid>
Hello, bound world!
<Button Name="btnSayIt" Click="btnSayHello_Click"
Using the DataContext
VerticalAlignment="Center"
The UpdateSourceTrigger
HorizontalAlignment="Center">Say hello!</Button>
property
</Grid>
Responding to changes
</Window>
Value conversion with
IValueConverter
The StringFormat property
using System; Debugging data bindings
using System.Speech.Synthesis;
using System.Windows;
Commands
namespace WpfTutorialSamples.Audio_and_Video
Introduction
{
Using commands
public partial class SpeechSynthesisSample :
Implementing custom
Window
commands
{
public SpeechSynthesisSample()
{
Common interface
InitializeComponent();
controls
}
The Menu control
private void btnSayHello_Click(object The ContextMenu
sender, RoutedEventArgs e) The ToolBar control
{ The StatusBar control
SpeechSynthesizer The Ribbon Control
speechSynthesizer = new SpeechSynthesizer();
speechSynthesizer.Speak("Hello,
world!"); Rich Text controls
} Introduction
} The
} FlowDocumentScrollViewer
control
The
FlowDocumentPageViewer
control
The FlowDocumentReader
control
Creating a FlowDocument
from Code-behind
Advanced FlowDocument
content
This is pretty much as simple as it gets, and since the screenshot really The RichTextBox control
doesn't help a lot in demonstrating speech synthesis, I suggest that you try
building the example yourself, to experience it.
Misc. controls
Controlling pronunciation
The Border control
The SpeechSynthesizer can do more than that though. Through the use of The Slider control
the PromptBuilder class, we can get much more control of how a sentence is The ProgressBar control
spoken.
This next example, which is an extension of the first example, will The WebBrowser control
illustrate that: The WindowsFormsHost
control
<Window
x:Class="WpfTutorialSamples.Audio_and_Video.SpeechSynthesisP
The TabControl
Using the TabControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta Tab positions
Styling the TabItems
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="SpeechSynthesisPromptBuilderSample"
List controls
Height="150" Width="150">
<Grid> The ItemsControl
<Button Name="btnSayIt" Click="btnSayHello_Click" The ListBox control
VerticalAlignment="Center" The ComboBox control
HorizontalAlignment="Center">Say hello!</Button>
</Grid>
</Window> The ListView control
Introduction
A simple ListView
ListView, data binding and
using System;
ItemTemplate
using System.Speech.Synthesis;
ListView with a GridView
using System.Windows;
How-to: Left aligned column
names
namespace WpfTutorialSamples.Audio_and_Video
ListView grouping
{
ListView sorting
public partial class
How-to: ListView with
SpeechSynthesisPromptBuilderSample : Window
column sorting
{
ListView filtering
public
SpeechSynthesisPromptBuilderSample()
{
InitializeComponent();
The TreeView control
} Introduction
A simple TreeView
private void btnSayHello_Click(object TreeView, data binding and
sender, RoutedEventArgs e) multiple templates
{ Handling
PromptBuilder promptBuilder = new Selection/Expansion state
PromptBuilder(); Lazy loading TreeView items
promptBuilder.AppendText("Hello
world");
The DataGrid control
PromptStyle promptStyle = new
Introduction
PromptStyle();
Custom columns
promptStyle.Volume =
Details row
PromptVolume.Soft;
promptStyle.Rate =
PromptRate.Slow;
Styles
promptBuilder.StartStyle(promptStyle); Introduction
promptBuilder.AppendText("and Using styles
hello to the universe too."); Triggers
promptBuilder.EndStyle(); Multi triggers
Trigger animations
promptBuilder.AppendText("On this
day, ");
Misc.
promptBuilder.AppendTextWithHint(DateTime.Now.ToShortDateStr The DispatcherTimer
SayAs.Date);
promptBuilder.AppendText(", we're
Audio & Video
gathered here to learn");
Playing audio
promptBuilder.AppendText("all",
Playing video
PromptEmphasis.Strong);
How-to: Complete media
promptBuilder.AppendText("about");
player
Speech synthesis
promptBuilder.AppendTextWithHint("WPF", SayAs.SpellOut);
Speech recognition
SpeechSynthesizer
speechSynthesizer = new SpeechSynthesizer();
speechSynthesizer.Speak(promptBuilder);
}
}
}
This is where it gets interesting. Try running the example and see how nicely
this works. By supplying the SpeechSynthesizer with something more than
just
a text string, we can get a lot of control of how the various parts of the
sentence are spoken. In this case, the application will say the following:
Hello world and hello to the universe too. On this day, <today's date>, we're
gathered here to learn all about WPF.
Now try sending that directly to the SpeechSynthesizer and you'll probably
giggle a bit of the result. What we do instead is guide the Speak() method
into
how the various parts of the sentence should be used. First of all, we ask
WPF to speak the "and hello to the universe too"-part in a lower volume and
a
slower rate, as if it was whispered.
The next part that doesn't just use default pronunciation is the date. We use
the special SayAs enumeration to specify that the date should be read out as
an actual date and not just a set of numbers, spaces and special characters.
We also ask that the word "all" is spoken with a stronger emphasis, to make
the sentence more dynamic, and in the end, we ask that the word "WPF" is
spelled out (W-P-F) instead of being pronounced as an actual word.
All in all, this allows us to make the SpeechSynthesizer a lot easier to
understand!
Summary
Making your WPF application speak is very easy, and by using the
PromptBuilder class, you can even get a lot of control of how your words are
spoken. This
is a very powerful feature, but it might not be relevant to a lot of
today's applications. It's still very cool though!
Previous Next
Download
PDF!
Back to Top
Home Contact Us
Download as PDF
Speech recognition (making WPF
listen) Download this entire
tutorial as PDF right
now!
About WPF
In the previous article we discussed how we could transform text into spoken
What is WPF?
words, using the SpeechSynthesizer class. In this article we'll go the other
WPF vs. WinForms
way around, by turning spoken words into text. To do that, we'll be using the
SpeechRecognition class, which resides in the System.Speech
assembly.
This assembly is not a part of your solutions by default, but we can easily add
it. Depending on which version of Visual Studio you use, the
process looks Getting started
something like this: Visual Studio Express
Hello, WPF!
XAML
What is XAML?
Basic XAML
Events in XAML
A WPF application
Introduction
The Window
Working with App.xaml
Command-line parameters
Resources
Handling exceptions
Basic controls
The TextBlock control
The TextBlock control - Inline
formatting
The Label control
The TextBox control
The CheckBox control
With that taken care of, let's start out with an extremely simple speech Panels
recognition example: Introduction to WPF Panels
The Canvas
<Window The WrapPanel
x:Class="WpfTutorialSamples.Audio_and_Video.SpeechRecognitio The StackPanel
The DockPanel
The Grid
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta The Grid - Rows & Columns
The Grid - Units
The Grid - Spanning
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" The Grid - GridSplitter
Title="SpeechRecognitionTextSample" Height="200" Using the Grid: A contact
Width="300"> form
<DockPanel Margin="10">
<TextBox Margin="0,10" Name="txtSpeech"
AcceptsReturn="True" /> Data binding
</DockPanel>
Introduction
</Window>
Hello, bound world!
Using the DataContext
The UpdateSourceTrigger
using System; property
using System.Speech.Recognition; Responding to changes
using System.Windows; Value conversion with
IValueConverter
namespace WpfTutorialSamples.Audio_and_Video The StringFormat property
{ Debugging data bindings
public partial class SpeechRecognitionTextSample :
Window
{ Commands
public SpeechRecognitionTextSample() Introduction
{ Using commands
InitializeComponent(); Implementing custom
SpeechRecognizer speechRecognizer commands
= new SpeechRecognizer();
}
} Common interface
}
controls
The Menu control
The ContextMenu
The ToolBar control
The StatusBar control
The Ribbon Control
This first example will allow you to dictate text to your application, which is
Misc. controls
great, but what about commands? Windows and WPF will actually work
The Border control
together
here and turn your buttons into commands, reachable through
The Slider control
speech, without any extra work. Here's an example:
The ProgressBar control
The WebBrowser control
<Window
The WindowsFormsHost
x:Class="WpfTutorialSamples.Audio_and_Video.SpeechRecognitio
control
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
The TabControl
Using the TabControl
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Tab positions
Title="SpeechRecognitionTextCommandsSample" Styling the TabItems
Height="200" Width="300">
<DockPanel Margin="10">
<WrapPanel DockPanel.Dock="Top"> List controls
<Button Name="btnNew" The ItemsControl
Click="btnNew_Click">New</Button> The ListBox control
<Button Name="btnOpen" The ComboBox control
Click="btnOpen_Click">Open</Button>
<Button Name="btnSave"
Click="btnSave_Click">Save</Button>
The ListView control
</WrapPanel>
You can try running the example and then speaking out one of the
commands, e.g. "New" or "Open". This actually allows you to dictate text to
the TextBox,
while at the same time invoking commands from the user
interface - pretty cool indeed!
Specific commands
In the above example, Windows will automatically go into dictation mode as
soon as focus is given to a text box. Windows will then try to distinguish
between dictation and commands, but this can of course be difficult in certain
situations.
So while the above examples have been focusing on dictation and interaction
with UI elements, this next example will focus on the ability to listen for and
interpret specific commands only. This also means that dictation will be
ignored completely, even though text input fields have focus.
For this purpose, we will use the SpeechRecognitionEngine class instead
of the SpeechRecognizer class. A huge difference
between the two is that
the SpeechRecognitionEngine class doesn't require the Windows speech
recognition to be running and won't take you
through the voice recognition
guide. Instead, it will use basic voice recognition and listen only for grammar
which you feed into the class.
In the next example, we'll feed a set of commands into the recognition
engine. The idea is that it should listen for two words: A command/property
and a
value, which in this case will be used to change the color, size and
weight of the text in a Label control, solely based on your voice commands.
Before I
show you the entire code sample, I want to focus on the way we add
the commands to the engine. Here's the code:
grammarBuilder.Append(valueChoices);
speechRecognizer.LoadGrammar(new Grammar(grammarBuilder));
We use a GrammarBuilder to build a set of grammar rules which we can
load into the SpeechRecognitionEngine. It has several append methods,
with
the simplest one being Append(). This method takes a list of choices. We
create a Choices instance, with the first part of the
instruction - the
command/property which we want to access. These choices are added to the
builder with the Append() method.
Now, each time you call an append method on the GrammarBuilder, you
instruct it to listen for a word. In our case, we want it to listen for two words,
so
we create a secondary set of choices, which will hold the value for the
designated command/property. We add a range of values for each of the
possible
commands - one set of values for the weight command, one set of
values for the color command and one set of values for the size command.
They're all added
to the same Choices instance and then appended to the
builder.
In the end, we load it into the SpeechRecognitionEngine instance by calling
the LoadGrammer() method, which takes a Grammar instance as
parameter
- in this case based on our GrammarBuilder instance.
So, with that explained, let's take a look at the entire example:
<Window
x:Class="WpfTutorialSamples.Audio_and_Video.SpeechRecognitio
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presenta
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="SpeechRecognitionCommandsSample"
Height="200" Width="325"
Closing="Window_Closing">
<DockPanel>
<WrapPanel DockPanel.Dock="Bottom"
HorizontalAlignment="Center" Margin="0,10">
<ToggleButton Name="btnToggleListening"
Click="btnToggleListening_Click">Listen</ToggleButton>
</WrapPanel>
<Label Name="lblDemo" HorizontalAlignment="Center"
VerticalAlignment="Center" FontSize="48">Hello, world!
</Label>
</DockPanel>
</Window>
using System;
using System.Globalization;
using System.Speech.Recognition;
using System.Windows;
using System.Windows.Media;
namespace WpfTutorialSamples.Audio_and_Video
{
public partial class
SpeechRecognitionCommandsSample : Window
{
private SpeechRecognitionEngine
speechRecognizer = new SpeechRecognitionEngine();
public SpeechRecognitionCommandsSample()
{
InitializeComponent();
speechRecognizer.SpeechRecognized
+= speechRecognizer_SpeechRecognized;
GrammarBuilder grammarBuilder =
new GrammarBuilder();
Choices commandChoices = new
Choices("weight", "color", "size");
grammarBuilder.Append(commandChoices);
speechRecognizer.LoadGrammar(new
Grammar(grammarBuilder));
speechRecognizer.SetInputToDefaultAudioDevice();
}
private void
btnToggleListening_Click(object sender, RoutedEventArgs e)
{
if(btnToggleListening.IsChecked ==
true)
speechRecognizer.RecognizeAsync(RecognizeMode.Multiple);
else
speechRecognizer.RecognizeAsyncStop();
}
private void
speechRecognizer_SpeechRecognized(object sender,
SpeechRecognizedEventArgs e)
{
lblDemo.Content = e.Result.Text;
if(e.Result.Words.Count == 2)
{
string command =
e.Result.Words[0].Text.ToLower();
string value =
e.Result.Words[1].Text.ToLower();
switch(command)
{
case "weight":
FontWeightConverter weightConverter = new
FontWeightConverter();
lblDemo.FontWeight =
(FontWeight)weightConverter.ConvertFromString(value);
break;
case "color":
lblDemo.Foreground = new
SolidColorBrush((Color)ColorConverter.ConvertFromString(valu
break;
case "size":
switch(value)
{
case "small":
lblDemo.FontSize = 12;
break;
case "medium":
lblDemo.FontSize = 24;
break;
case "large":
lblDemo.FontSize = 48;
break;
}
break;
}
}
}
On the screenshot, you see the resulting application, after I've used the voice
commands "weight bold" and "color blue" - pretty cool, right?
The grammar aspects of the example has already been explained and the
interface is very simple, so let's focus on the rest of the Code-behind.
We use a ToggleButton to enable or disable listening, using the
RecognizeAsync() and RecognizeAsyncStop() methods. The
RecognizeAsync()
takes a parameter which informs the recognition engine if
it should do a single recognition or multiple recognitions. For our example, we
want to give
several commands, so Multiple is used. So, to enable listening,
just click the button, and to disable it, just click it again. The state is visually
represented by the button, which will be "down" when enabled and normal
when disabled.
Now, besides building the Grammar, the most interesting part is where we
interpret the command. This is done in the SpeechRecognized
event, which
we hook up to in the constructor. We use the fully recognized text to update
the demo label, to show the latest command, and then we use the
Words
property to dig deeper into the actual command.
First off, we check that it has exactly two words - a command/property and a
value. If that is the case, we check the command part first, and for each
For the weight and color commands, we can convert the value into
something the label can understand automatically, using a converter, but for
the sizes, we
interpret the given values manually, since the values I've
chosen for this example can't be converted automatically. Please be aware
that you should handle
exceptions in all cases, since a command like "weight
blue" will try to assign the value blue to the FontWeight, which will naturally
result in an
exception.
Summary
As you can hopefully see, speech recognition with WPF is both easy and
very powerful - especially the last example should give you a good idea just
how
powerful! With the ability to use dictation and/or specific voice
commands, you can really provide excellent means for alternative input in
your
applications.
Previous
Download
PDF!
Back to Top