Go Top
advertise here!!!

Library || READ MORE || DOWNLOAD PDF || QUESTION ANSWERS || HOME

  • About WPF ↓

    What is WPF

    WPF, which stands for Windows Presentation Foundation, is Microsoft's latest approach to a GUI framework, used with the .NET framework.

    But what IS a GUI framework? GUI stands for Graphical User Interface, and 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.

    A GUI framework allows you to create an application with a wide range of GUI 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 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 applications.

    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 the next chapter, there are quite a few differences between the two frameworks, but their purpose is the same: To make it easy to create applications with a great GUI.

    In the next chapter, we will look at the differences between WinForms and WPF.

    WPF vs. WinForms

    In the previous chapter, we talked about what WPF is and a little bit about WinForms. In this chapter, I will try to compare the two, because while they do serve the same purpose, there is a LOT of differences between them. If 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.

    The single most important difference between WinForms and WPF is the fact that while WinForms is simply a layer on top of the standard Windows 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 ever worked with a framework that depends on Win32/WinAPI.

    A great example of this is a button with an image and text on it. This is not a standard Windows control, so WinForms doesn't offer you this possibility out 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 and various states (e.g. untouched, hovered, pressed). The WPF button is "look-less", as are most other WPF controls, which means that it can contain a range of other controls inside of it. You want a button with an image and some text? Just put an Image and a TextBlock control inside of the button and you're done! You simply don’t get this kind of flexibility out of the standard WinForms controls, which is why there's a big market for rather 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 created for just the scenario you need it for. At least that's how it feels in the beginning, where you find yourself creating templates to make a ListView with an image and some nicely aligned text, something that the WinForms ListViewItem does in a single line of code.

    This was just one difference, but as you work with WPF, you will realize that it is in fact the underlying reason for many of the other differences - WPF is simply just doing things in its own way, for better and for worse. You're no 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.

    WPF advantages

    • It's newer and thereby more in tune with current standards
    • Microsoft is using it for a lot of new applications, e.g. Visual Studio
    • It's more flexible, so you can do more things without having to write or buy new controls
    • When you do need to use 3rd party controls, the developers of these controls will likely be more focused on WPF because it's newer
    • XAML makes it easy to create and edit your GUI, and allows the work 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 and layout
    • Uses hardware acceleration for drawing the GUI, for better performance
    • It allows you to make user interfaces for both Windows applications and web applications (Silverlight/XBAP)

    WinForms advantages

    • It's older and thereby more tried and tested
    • There are already a lot of 3rd party controls that you can buy or get for free
    • 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
    advertise here!!!
  • Get Start to Read ↓

    Visual Studio Express

    WPF is, as already described, a combination of XAML (markup) and C#/VB.NET/any other .NET language. All of it can be edited in any text editor, even Notepad included in Windows, and then compiled from the 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.

    The preferred choice for a .NET/WPF IDE is Visual Studio, which costs a lot quite a bit of money though. Luckily, Microsoft has decided to make it easy 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 everything that you need to get started learning WPF and make real applications.

    The latest version, as of writing this text, is Microsoft Visual Studio Express 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-windows-desktop.

    After downloading and installing, you can use this product for 30 days without any registration. After that, you will need to register it on the above mentioned website, which is also completely free.

    Hello, WPF!

    The first and very classic example in pretty much any programming tutorial is the "Hello, world!" example, but in this tutorial we'll go nuts and change that into "Hello, WPF!" instead. The goal is simply to get this piece of text onto the 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 instructions on how to get it). If you're using another product, you will have to adapt the instructions to your product.

    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# whenever code is involved, so you should select that from the list of templates, and since we'll be creating Windows applications, you should select Windows from the tree. This will give you a list of possible Windows application types to the right, where you should select a WPF Application. I 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.

    Your new project will have a couple of files, but we will focus on just one of them now: MainWindox.xaml. This is the applications primary window, the one shown first when launching the application, unless you specifically change this. The XAML code found in it (XAML is discussed in details in another chapter of this tutorial) should look something like this:

    <Window x:Class="WpfApplication1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"> <Grid> </Grid> </Window>

    This is the base XAML that Visual Studio creates for our window, all parts of it explained in the chapters on XAML and "The Window". You can actually run the application now (select Debug -> Start debugging or press F5) to see the empty window that our application currently consists of, but now it's time to get our message on the screen.

    We'll do it by adding a TextBlock control to the Grid panel, with our aforementioned message as the content:

    <Window x:Class="WpfApplication1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"> <Grid> <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="72"> Hello, WPF! </TextBlock> </Grid> </Window>

    Try running the application now (select Debug -> Start debugging or press F5) and see the beautiful result of your hard work - your first WPF application:

    Hello, WPF! - the result

    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 property to get bigger text. All of these concepts will be treated in later articles.

    Congratulations on making it this far. Now go read the rest of the tutorial and soon you will master WPF!

    advertise here!!!
  • XAML ↓

    advertise here!!!

    What is XAML?

    XAML, which stands for eXtensible Application Markup Language, is Microsoft's variant of XML for describing a GUI. In previous GUI frameworks, like WinForms, a GUI was created in the same language that you would use 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.

    This is not really a XAML tutorial, but I will briefly tell you about how you use it, because it's such an essential part of WPF. Whether you're creating a 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 and has access to manipulate with the XAML controls.

    In the next chapters, we will have a look at how XAML works and how you use it to create your interface.

    Basic XAML

    In the previous chapter, we talked about what XAML is and what you use it for, but how do you create a control in XAML? As you will see from the next example, creating a control in XAML is as easy as writing it's name, surrounded by angle brackets. For instance, a Button looks like this:

    <Button>
    

    XAML tags has to be ended, either by writing the end tag or by putting a forward slash at the end of the start tag:

    <Button></Button>
    

    Or

    <Button />
    

    A lot of controls allow you to put content between the start and end tags, which is then the content of the control. For instance, the Button control allows you to specify the text shown on it between the start and end tags:

    <Button>A button</Button>
    

    HTML is not case-sensitive, but XAML is, because the control name has to 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:

    <Button FontWeight="Bold" Content="A button" />
    

    We set the FontWeight property, giving us bold text, and then we set the Content property, which is the same as writing the text between the start and end tag. However, all attributes of a control may also be defined like this, where they appear as child tags of the main control, using the Control-Dot-Property notation:

    <Button>
        <Button.FontWeight>Bold</Button.FontWeight>
        <Button.Content>A button</Button.Content>
    </Button>
    

    The result is exactly the same as above, so in this case, it's all about syntax and nothing else. However, a lot of controls allow content other than text, for instance other controls. Here's an example where we have text in different colors on the same button by using several TextBlock controls inside of the Button:

    <Button>
        <Button.FontWeight>Bold</Button.FontWeight>
        <Button.Content>
            <WrapPanel>
                <TextBlock Foreground="Blue">Multi</TextBlock>
                <TextBlock Foreground="Red">Color</TextBlock>
                <TextBlock>Button</TextBlock>
            </WrapPanel>
        </Button.Content>
    </Button>
    

    The Content property only allows for a single child element, so we use a WrapPanel to contain the differently colored blocks of text. Panels, like the WrapPanel, plays an important role in WPF and we will discuss them in much more details later on - for now, just consider them as containers for other controls.

    <Button FontWeight="Bold">
        <WrapPanel>
            <TextBlock Foreground="Blue">Multi</TextBlock>
            <TextBlock Foreground="Red">Color</TextBlock>
            <TextBlock>Button</TextBlock>
        </WrapPanel>
    </Button>
    

    Code vs. XAML

    Hopefully the above examples show you that XAML is pretty easy to write, but with a lot of different ways of doing it, and if you think that the above example is a lot of markup to get a button with text in different colors, then try comparing it to doing the exact same thing in C#:

    Button btn = new Button();
    btn.FontWeight = FontWeights.Bold;
    
    WrapPanel pnl = new WrapPanel();
    
    TextBlock txt = new TextBlock();
    txt.Text = "Multi";
    txt.Foreground = Brushes.Blue;
    pnl.Children.Add(txt);
    
    txt = new TextBlock();
    txt.Text = "Color";
    txt.Foreground = Brushes.Red;
    pnl.Children.Add(txt);
    
    txt = new TextBlock();
    txt.Text = "Button";
    pnl.Children.Add(txt);
    
    btn.Content = pnl;
    pnlMain.Children.Add(btn);
    

    Of course the above example could be written less explicitly and using more syntactical sugar, but I think the point still stands: XAML is pretty short and concise for describing interfaces.

    Events in XAML

    Most modern UI frameworks are event driven and so is WPF. All of the controls, including the Window (which also inherits the Control class) exposes a range of events that you may subscribe to. You can subscribe to 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 there to respond to the user's interaction with your application using the mouse or the keyboard. On most controls you will find events like KeyDown, KeyUp, MouseDown, MouseEnter, MouseLeave, MouseUp and several others.

    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 piece of code in your Code-behind file. Have a look at this example:

    <Window x:Class="WpfTutorialSamples.XAML.EventsSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="EventsSample" Height="300" Width="300">
    	<Grid Name="pnlMainGrid" MouseUp="pnlMainGrid_MouseUp" Background="LightBlue">        
    		
        </Grid>
    </Window>
    

    Notice how we have subscribed to the MouseUp event of the Grid by writing a method name. This method needs to be defined in code-behind, using the correct event signature. In this case it should look like this:

    private void pnlMainGrid_MouseUp(object sender, MouseButtonEventArgs e)
    {
    	MessageBox.Show("You clicked me at " + e.GetPosition(this).ToString());
    }
    

    The MouseUp event uses a delegate called MouseButtonEventHandler, which you subscribe to. It has two parameters, a sender (the control which raised the event) and a MouseButtonEventArgs object that will contain useful information. We use it in the example to get the position of the mouse cursor and tell the user about it.

    Several events may use the same delegate type - for instance, both MouseUp and MouseDown uses the MouseButtonEventHandler delegate, while the MouseMove event uses the MouseEventHandler delegate. When defining the event handler method, you need to know which delegate it uses and if you don't know that, you can look it up in the documentation.

    Fortunately, Visual Studio can help us to generate a correct event handler for an event. The easiest way to do this is to simply write the name of the event in XAML and then let the IntelliSense of VS do the rest for you:

    Visual Studio helping to create a new event handler

    When you select <New Event Handler> Visual Studio will generate an appropriate event handler in your Code-behind file. It will be named <control 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.

    Subscribing to an event from Code-behind

    The most common way to subscribe to events is explained above, but there 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:

    using System;
    using System.Windows;
    using System.Windows.Input;
    
    
    namespace WpfTutorialSamples.XAML
    {
    	public partial class EventsSample : Window
    	{
    		public EventsSample()
    		{
    			InitializeComponent();
    			pnlMainGrid.MouseUp += new MouseButtonEventHandler(pnlMainGrid_MouseUp);
    		}
    
    		private void pnlMainGrid_MouseUp(object sender, MouseButtonEventArgs e)
    		{
    			MessageBox.Show("You clicked me at " + e.GetPosition(this).ToString());
    		}
    
    	}
    }
    

    Once again, you need to know which delegate to use, and once again, Visual Studio can help you with this. As soon as you write:

    pnlMainGrid.MouseDown +=

    Visual Studio will offer its assistance:

    Visual Studio helping to create a new Code-behind event handler

    Simply press the [Tab] key twice to have Visual Studio generate the correct 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.

    advertise here!!!
  • A WPF application ↓

    advertise here!!!

    A WPF Application - Introduction

    In this tutorial, our primary focus will be on using WPF to create applications. As you may know, .NET can be executed on all platforms which have a .NET implementation, but the most common platform is still Microsoft Windows. 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.

    A WPF application requires the .NET framework to run, just like any other .NET application type. Fortunately, Microsoft has been including the .NET 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 be able to run your WPF application.

    In the following chapters we will have a look at the structure and various aspects of a WPF application.

    The Window

    When creating a WPF application, the first thing you will meet is the Window class. It serves as the root of a window and provides you with the standard border, title bar and maximize, minimize and close buttons. A WPF window is 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:

    <Window x:Class="WpfApplication1.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="300" Width="300">
        <Grid>
    
        </Grid>
    </Window>
    
    The x:class attribute tells the XAML file which class to use, in this case Window1, which Visual Studio has created for us as well. You will find it in the project tree in VS, as a child node of the XAML file. By default, it looks something like this:
    using System;
    using System.Windows;
    using System.Windows.Controls;
    //…more using statements
    
    namespace WpfApplication1
    {
        /// <summary>
        /// Interaction logic for Window1.xaml
        /// </summary>
        public partial class Window1 : Window
        {
            public Window1()
            {
                InitializeComponent();
            }
        }
    }
    

    As you can see, the Window1 class is definied as partial, because it's being combined with your XAML file in runtime to give you the full window. This is actually what the call to InitializeComponent() does, which is why it's required to get a full functioning window up and running.

    If we go back to the XAML file, you will notice a couple of other interesting attributes on the Window element, like Title, which defines the title of the window (shown in the title bar) as well as the starting width and height. There are also a couple of namespace definitions, which we will talk about in the XAML chapters.

    You will also notice that Visual Studio has created a Grid control for us inside the Window. The Grid is one of the WPF panels, and while it could be any panel or control, the Window can only have ONE child control, so a Panel, which in turn can contain multiple child controls, is usually a good choice. Later in this tutorial, we will have a much closer look into the different types of panels that you can use, as they are very important in WPF.

    Important Window properties

    The WPF Window class has a bunch of interesting attributes that you may set to control the look and behavior of your application window. Here's a short list of the most interesting ones:

    Icon - Allows you to define the icon of the window, which is usually shown in the upper right corner, right before the window title.

    ResizeMode - This controls whether and how the end-user can resize your window. The default is CanResize, which allows the user to resize the window like any other window, either by using the maximize/minimize buttons or by dragging one of the edges. CanMinimize will allow the user to minimize the window, but not to maximize it or drag it bigger or smaller. NoResize is the strictest one, where the maximize and minimize buttons are removed and the window can't be dragged bigger or smaller.

    ShowInTaskbar - The default is true, but if you set it to false, your window won't be represented in the Windows taskbar. Useful for non-primary windows or for applications that should minimize to the tray.

    SizeToContent - Decide if the Window should resize itself to automatically fit its content. The default is Manual, which means that the window doesn't automatically resize. Other options are Width, Height and WidthAndHeight, and each of them will automatically adjust the window size horizontally, vertically or both.

    Topmost - The default is false, but if set to true, your Window will stay on top of other windows unless minimized. Only useful for special situations.

    WindowStartupLocation - Controls the initial position of your window. The default is Manual, which means that the window will be initially positioned according to the Top and Left properties of your window. Other options are CenterOwner, which will position the window in the center of it's owner window, and CenterScreen, which will position the window in the center of the screen.

    WindowState - Controls the initial window state. It can be either Normal, Maximized or Minimized. The default is Normal, which is what you should 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 move on to the next chapter.

    Working with App.xaml

    App.xaml is the declarative starting point of your application. Visual Studio will automatically create it for you when you start a new WPF application, including a Code-behind file called App.xaml.cs. They work much like for a 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 Windows application. .NET will go to this class for starting instructions and then start the desired Window or Page from there. This is also the place to subscribe to important application events, like application start, unhandled exceptions and so on. More about that later.

    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, for instance global styles. This will be discussed in detail later on.

    App.xaml structure

    When creating a new application, the automatically generated App.xaml will look something like this:

    <Application x:Class="WpfTutorialSamples.App"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 StartupUri="MainWindow.xaml">
        <Application.Resources>
    
        </Application.Resources>
    </Application>
    

    The main thing to notice here is the StartupUri property. This is actually the part that instructs which Window or Page to start up when the application is launched. In this case, MainWindow.xaml will be started, but if you would like 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 window is displayed. In that case, you can remove the StartupUri property and value and then do it all from Code-Behind instead. This will be demonstrated below.

    App.xaml.cs structure

    The matching App.xaml.cs will usually look like this for a new project:

    using System;
    using System.Collections.Generic;
    using System.Windows;
    
    namespace WpfTutorialSamples
    {
    	public partial class App : Application
    	{
    
    	}
    }
    

    You will see how this class extends the Application class, allowing us to do stuff on the application level. For instance, you can subscribe to the Startup event, where you can manually create your starting window.

    Command-line parameters in WPF

    Command-line parameters are a technique where you can pass a set of parameters to an application that you wish to start, to somehow influence it. The most common example is to make the application open with a specific 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]):

    notepad.exe c:\Windows\win.ini

    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!

    Command-line parameters are passed to your WPF application through the Startup event, which we subscribed to in the App.xaml article. We will do the same in this example, and then use the value passed on to through the method arguments. First, the App.xaml file:

    <Application x:Class="WpfTutorialSamples.App"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    			 Startup="Application_Startup">
        <Application.Resources></Application.Resources>
    </Application>
    

    All we do here is to subscribe to the Startup event, replacing the StartupUri property. The event is then implemented in App.xaml.cs:

    using System;
    using System.Collections.Generic;
    using System.Windows;
    
    namespace WpfTutorialSamples
    {
    	public partial class App : Application
    	{
    
    		private void Application_Startup(object sender, StartupEventArgs e)
    		{
    			MainWindow wnd = new MainWindow();
    			if(e.Args.Length == 1)
    				MessageBox.Show("Now opening file: \n\n" + e.Args[0]);
    			wnd.Show();
    		}
    	}
    }
    

    The StartupEventArgs is what we use here. It's passed into the Application 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 space is inside a quoted string.

    Testing the command-line parameter

    If you run the above example, nothing will happen, because no command-line parameters have been specified. Fortunately, Visual Studio makes it easy to test this in your application. From the Project menu select "[Project name] properties" and then go to the Debug tab, where you can define a command-line parameter. It should look something like this:

    The command-line project settings

    Try running the application and you will see it respond to your parameter.

    Of course, the message isn't terribly useful. Instead you might want to either pass it to the constructor of your main window or call a public open method on it, like this:

    using System;
    using System.Collections.Generic;
    using System.Windows;
    
    namespace WpfTutorialSamples
    {
    	public partial class App : Application
    	{
    
    		private void Application_Startup(object sender, StartupEventArgs e)
    		{
    			MainWindow wnd = new MainWindow();
    			// The OpenFile() method is just an example of what you could do with the
    			// parameter. The method should be declared on your MainWindow class, where
    			// you could use a range of methods to process the passed file path
    			if(e.Args.Length == 1)
    				wnd.OpenFile(e.Args[0]);
    			wnd.Show();
    		}
    	}
    }
    

    Command-line possibilities

    In this example, we test if there is exactly one argument and if so, we use it as a filename. In a real world example, you might collect several arguments and even use them for options, e.g. toggling a certain feature on or off. You would 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.

    Resources

    WPF introduces a very handy concept: The ability to store data as a resource, either locally for a control, locally for the entire window or globally for the entire application. The data can be pretty much whatever you want, 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.

    The concept is used a lot for styles and templates, which we'll discuss later on in this tutorial, but as it will be illustrated in this chapter, you can use it for many other things as well. Allow me to demonstrate it with a simple example:

    <Window x:Class="WpfTutorialSamples.WPF_Application.ResourceSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:sys="clr-namespace:System;assembly=mscorlib"
            Title="ResourceSample" Height="150" Width="350">
        <Window.Resources>
            <sys:String x:Key="strHelloWorld">Hello, world!</sys:String>
        </Window.Resources>
        <StackPanel Margin="10">
            <TextBlock Text="{StaticResource strHelloWorld}" FontSize="56" />
            <TextBlock>Just another "<TextBlock Text="{StaticResource strHelloWorld}" />" 
            example, but with resources!</TextBlock>
        </StackPanel>
    </Window>
    

    A simple resource sample

    Resources are given a key, using the x:Key attribute, which allows you to reference it from other parts of the application by using this key, in combination with the StaticResource markup extension. In this example, I just store a simple string, which I then use from two different TextBlock controls.

    StaticResource vs. DynamicResource

    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.

    The main difference is that a static resource is resolved only once, which is at the point where the XAML is loaded. If the resource is then changed later on, this change will not be reflected where you have used the StaticResource.

    A DynamicResource on the other hand, is resolved once it's actually needed, and then again if the resource changes. Think of it as binding to a static value vs. binding to a function that monitors this value and sends it to you each time it's changed - it's not exactly how it works, but it should give you a better idea of when to use what. Dynamic resources also allows you to use resources which are not even there during design time, e.g. if you add them from Code-behind during the startup of the application.

    More resource types

    Sharing a simple string was easy, but you can do much more. In the next example, I'll also store a complete array of strings, along with a gradient brush to be used for the background. This should give you a pretty good idea of just how much you can do with resources:

    <Window x:Class="WpfTutorialSamples.WPF_Application.ExtendedResourceSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:sys="clr-namespace:System;assembly=mscorlib"
            Title="ExtendedResourceSample" Height="160" Width="300"
            Background="{DynamicResource WindowBackgroundBrush}">
        <Window.Resources>
            <sys:String x:Key="ComboBoxTitle">Items:</sys:String>
    
            <x:Array x:Key="ComboBoxItems" Type="sys:String">
                <sys:String>Item #1</sys:String>
                <sys:String>Item #2</sys:String>
                <sys:String>Item #3</sys:String>
            </x:Array>
    
            <LinearGradientBrush x:Key="WindowBackgroundBrush">
                <GradientStop Offset="0" Color="Silver"/>
                <GradientStop Offset="1" Color="Gray"/>
            </LinearGradientBrush>
        </Window.Resources>
        <StackPanel Margin="10">
            <Label Content="{StaticResource ComboBoxTitle}" />
            <ComboBox ItemsSource="{StaticResource ComboBoxItems}" />
        </StackPanel>
    </Window>
    

    A more advanced example with several resource types

    This time, we've added a couple of extra resources, so that our Window now 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 entire window. So, as you can see, pretty much anything can be stored as a resource.

    Local and application wide resources

    For now, we have stored resources on a window-level, which means that you can access them from all over the window.

    If you only need a given resource for a specific control, you can make it more local by adding it to this specific control, instead of the window. It works exactly the same way, the only difference being that you can now only access from inside the scope of the control where you put it:

    <StackPanel Margin="10">
        <StackPanel.Resources>
            <sys:String x:Key="ComboBoxTitle">Items:</sys:String>
        </StackPanel.Resources>
        <Label Content="{StaticResource ComboBoxTitle}" />
    </StackPanel>
    

    In this case, we add the resource to the StackPanel and then use it from its child control, the Label. Other controls inside of the StackPanel could have 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.

    If you need the ability to access the resource from several windows, this is possible as well. The App.xaml file can contain resources just like the window and any kind of WPF control, and when you store them in App.xaml, 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:

    <Application x:Class="WpfTutorialSamples.App"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:sys="clr-namespace:System;assembly=mscorlib"
                 StartupUri="WPF application/ExtendedResourceSample.xaml">
        <Application.Resources>
            <sys:String x:Key="ComboBoxTitle">Items:</sys:String>
        </Application.Resources>
    </Application>
    

    Using it is also the same - WPF will automatically go up the scope, from the local control to the window and then to App.xaml, to find a given resource:

    <Label Content="{StaticResource ComboBoxTitle}" />
    

    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 Code-behind, each stored in a different scope:

    App.xaml:

    <Application x:Class="WpfTutorialSamples.App"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 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.ResourcesFromCodeBehindSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            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>
    
            <ListBox Name="lbResult" />
        </DockPanel>
    </Window>
    

    Code-behind:

    using System;
    using System.Windows;
    
    namespace WpfTutorialSamples.WPF_Application
    {
    	public partial class ResourcesFromCodeBehindSample : Window
    	{
    		public ResourcesFromCodeBehindSample()
    		{
    			InitializeComponent();
    		}
    
    		private void btnClickMe_Click(object sender, RoutedEventArgs e)
    		{
    			lbResult.Items.Add(pnlMain.FindResource("strPanel").ToString());
    			lbResult.Items.Add(this.FindResource("strWindow").ToString());
    			lbResult.Items.Add(Application.Current.FindResource("strApp").ToString());
    		}
    	}
    }
    

    Resources grabbed from Code-behind

    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.

    Handling exceptions in WPF

    If you're familiar with C# or any of the other .NET languages that you may use with WPF, then exception handling should not be new to you: Whenever you have a piece of code that are likely to throw an exception, then you should wrap it in a try-catch block to handle the exception gracefully. For instance, consider this example:

    private void Button_Click(object sender, RoutedEventArgs e)
    {
    	string s = null;
    	s.Trim();
    }
    

    Obviously it will go wrong, since I try to perform the Trim() method on a variable that's currently null. If you don't handle the exception, your application will crash and Windows will have to deal with the problem. As you can see, that isn't very user friendly:

    An unhandled exception, left for Windows to deal with

    In this case, the user would be forced to close your application, due to such a simple and easily avoided error. So, if you know that things might go wrong, then you should use a try-catch block, like this:

    private void Button_Click(object sender, RoutedEventArgs e)
    {
    	string s = null;
    	try
    	{
    		s.Trim();
    	}
    	catch(Exception ex)
    	{
    		MessageBox.Show("A handled exception just occurred: " + ex.Message, "Exception Sample", MessageBoxButton.OK, MessageBoxImage.Warning);
    	}
    }
    

    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 you handle all unhandled exceptions globally. This is done through the DispatcherUnhandledException event on the Application class. If subscribed to, WPF will call the subscribing method once an exception is thrown which is not handled in your own code. Here's a complete example, based on the stuff we just went through:

    <Window x:Class="WpfTutorialSamples.WPF_Application.ExceptionHandlingSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="ExceptionHandlingSample" Height="200" Width="200">
        <Grid>
            <Button HorizontalAlignment="Center" VerticalAlignment="Center" Click="Button_Click">
                Do something bad!
            </Button>
        </Grid>
    </Window>
    
    using System;
    using System.Windows;
    
    namespace WpfTutorialSamples.WPF_Application
    {
    	public partial class ExceptionHandlingSample : Window
    	{
    		public ExceptionHandlingSample()
    		{
    			InitializeComponent();
    		}
    
    		private void Button_Click(object sender, RoutedEventArgs e)
    		{
    			string s = null;
    			try
    			{
    				s.Trim();
    			}
    			catch(Exception ex)
    			{
    				MessageBox.Show("A handled exception just occurred: " + ex.Message, "Exception Sample",
                     MessageBoxButton.OK, MessageBoxImage.Warning);
    			}
    			s.Trim();
    		}
    	}
    }
    

    Notice that I call the Trim() method an extra time, outside of the try-catch block, so that the first call is handled, while the second is not. For the second one, we need the App.xaml magic:

    <Application x:Class="WpfTutorialSamples.App"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 DispatcherUnhandledException="Application_DispatcherUnhandledException"
                 StartupUri="WPF Application/ExceptionHandlingSample.xaml">
        <Application.Resources>
        </Application.Resources>
    </Application>
    
    using System;
    using System.Windows;
    
    namespace WpfTutorialSamples
    {
    	public partial class App : Application
    	{
    		private void Application_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
    		{
    			MessageBox.Show("An unhandled exception just occurred: " + e.Exception.Message, "Exception Sample",
                 MessageBoxButton.OK, MessageBoxImage.Warning);
    			e.Handled = true;
    		}
    	}
    }
    

    A locally handled exception

    A globally handled exception

    We handle the exception much like the local one, but with a slightly different text and image in the message box. Also, notice that I set the e.Handled property to true. This tells WPF that we're done dealing with this exception and nothing else should be done about it.

    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.

    advertise here!!!
  • Basic Controls ↓

    advertise here!!!

    The TextBlock control

    TextBlock is not a control, per se, since it doesn't inherit from the Control class, but it's used much like any other control in the WPF framework, so we'll call it a control to keep things simple.

    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 understanding is that a Label is for short, one-line texts (but may include e.g. an image), while the TextBlock works very well for multiline strings as well, 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.

    We already used a TextBlock control in the "Hello, WPF!" article, but for now, let's have a look at the TextBlock in its simplest form:

    <Window x:Class="WpfTutorialSamples.Basic_controls.TextBlockSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="TextBlockSample" Height="100" Width="200">
        <Grid>
    		<TextBlock>This is a TextBlock</TextBlock>
        </Grid>
    </Window>
    
    A simple TextBlock 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 TextBlock is simply a shortcut for setting the Text property of the TextBlock.

    For the next example, let's try a longer text to show how the TextBlock deals with that. I've also added a bit of margin, to make it look just a bit better:

    <Window x:Class="WpfTutorialSamples.Basic_controls.TextBlockSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="TextBlockSample" Height="100" Width="200">
        <Grid>
    		<TextBlock Margin="10">This is a TextBlock control and it comes with a very long text</TextBlock>
        </Grid>
    </Window>
    
    A simple TextBlock control with text that's too long to fit

    Dealing with long strings

    As you will soon realize from the screenshot, the TextBlock is perfectly capable of dealing with long, multiline texts, but it will not do anything by default. In this case the text is too long to be rendered inside the window, so WPF renders as much of the text as possible and then just stops.

    Fortunately, there are several ways of dealing with this. In the next example I'll show you all of them, and then I'll explain each of them afterwards:

    <Window x:Class="WpfTutorialSamples.Basic_controls.TextBlockSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="TextBlockSample" Height="200" Width="250">
        <StackPanel>
    		<TextBlock Margin="10" Foreground="Red">
    			This is a TextBlock control<LineBreak />
    			with multiple lines of text.
    		</TextBlock>
    		<TextBlock Margin="10" TextTrimming="CharacterEllipsis" Foreground="Green">
    			This is a TextBlock control with text that may not be rendered completely, 
                which will be indicated with an ellipsis.
    		</TextBlock>
    		<TextBlock Margin="10" TextWrapping="Wrap" Foreground="Blue">
    			This is a TextBlock control with automatically wrapped text, using the TextWrapping property.
    		</TextBlock>
    	</StackPanel>
    </Window>
    
    A TextBlock control showing several ways to deal with long strings

    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 their text content is too long in different ways:

    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 user makes the window bigger, the text will still wrap at the same position, even though there may now be room enough to fit the entire text onto one line.

    The green TextBlock uses the TextTrimming property with the value CharacterEllipsis to make the TextBlock show an ellipsis (...) when it can't fit any more text into the control. This is a common way of showing that there's more text, but not enough room to show it. This is great when you have text that might be too long but you absolutely don't want it to use more than one line. As an alternative to CharacterEllipsis you may use WordEllipsis, which will trim the text at the end of the last possible word instead of the last possible character, preventing that a word is only shown in part.

    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 into the previous line. Contrary to the first TextBlock, where we manually define where to wrap the text, this happens completely automatic and even better: It's also automatically adjusted as soon as the TextBlock get more or less space available. Try making the window in the example bigger or smaller and you will see how the wrapping is updated to match the situation.

    This was all about dealing with simple strings in the TextBlock. In the next 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 TextBlock control - Inline formatting

    In the last article we looked at the core functionality of the TextBlock control: Displaying a simple string and wrapping it if necessary. We even used 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 constructs all inherit from the Inline class, which means that they can be rendered inline, as a part of a larger text. As of writing, the supported 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.

    Bold, Italic and Underline

    These are probably the simplest types of inline elements. The names should tell you a lot about what they do, but we'll still give you a quick example on how to use them:

    <Window x:Class="WpfTutorialSamples.Basic_controls.TextBlockInlineSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="TextBlockInlineSample" Height="100" Width="300">
        <Grid>
    		<TextBlock Margin="10" TextWrapping="Wrap">
    			TextBlock with <Bold>bold</Bold>, <Italic>italic</Italic> 
                and <Underline>underlined</Underline> text.
    		</TextBlock>
        </Grid>
    </Window>
    
    A TextBlock control with inline bold, italic and underlined elements

    Much like with HTML, you just surround your text with a Bold tag to get bold text and so on. This makes it very easy to create and display diverse text in your applications.

    All three of these tags are just child classes of the Span element, each setting a specific property on the Span element to create the desired effect. For instance, the Bold tag just sets the FontWeight property on the underlying Span element, the Italic element sets the FontStyle and so on.

    LineBreak

    Simply inserts a line break into the text. Please see the previous chapter for an example where we use the LineBreak element.

    Hyperlink

    The Hyperlink element allows you to have links in your text. It's rendered with a style that suits your current Windows theme, which will usually be some sort of underlined blue text with a red hover effect and a hand mouse cursor. You can use the NavigateUri property to define the URL that you wish to navigate to. Here's an example:

    <Window x:Class="WpfTutorialSamples.Basic_controls.TextBlockHyperlinkSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="TextBlockHyperlinkSample" Height="100" Width="300">
    	<Grid>
    		<TextBlock Margin="10" TextWrapping="Wrap">
    			This text has a <Hyperlink RequestNavigate="Hyperlink_RequestNavigate"
                 NavigateUri="https://www.google.com">link</Hyperlink> in it.
    		</TextBlock>
    	</Grid>
    </Window>
    
    A TextBlock control using the Hyperlink element to create a clickable link

    The Hyperlink is also used inside of WPF Page's, where it can be used to navigate between pages. In that case, you won't have to specifically handle the RequestNavigate event, like we do in the example, but for launching external URL's from a regular WPF application, we need a bit of help from 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:

    private void Hyperlink_RequestNavigate(object sender, System.Windows.Navigation.RequestNavigateEventArgs e)
    {
    	System.Diagnostics.Process.Start(e.Uri.AbsoluteUri);
    }
    

    Run

    The Run element allows you to style a string using all the available properties of the Span element, but while the Span element may contain other inline elements, a Run element may only contain plain text. This makes the Span element more flexible and therefore the logical choice in most cases.

    Span

    The Span element doesn't have any specific rendering by default, but allows you to set almost any kind of specific rendering, including font size, style and weight, background and foreground colors and so on. The great thing about the Span element is that it allows for other inline elements inside of it, making it easy to do even advanced combinations of text and style. In the following example, I have used many Span elements to show you some of the many possibilities when using inline Span elements:

    <Window x:Class="WpfTutorialSamples.Basic_controls.TextBlockSpanSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="TextBlockSpanSample" Height="100" Width="300">
        <Grid>
    		<TextBlock Margin="10" TextWrapping="Wrap">
    			This <Span FontWeight="Bold">is</Span> a
    			<Span Background="Silver" Foreground="Maroon">TextBlock</Span>
    			with <Span TextDecorations="Underline">several</Span>
    			<Span FontStyle="Italic">Span</Span> elements,
    			<Span Foreground="Blue">
    				using a <Bold>variety</Bold> of <Italic>styles</Italic>
    			</Span>.
    		</TextBlock>
    	</Grid>
    </Window>
    
    A TextBlock control using a variety of differently styled Span elements for custom text formatting

    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, the Span element is a great choice.

    Formatting text from C#/Code-Behind

    As you can see, formatting text through XAML is very easy, but in some cases, you might prefer or even need to do it from your C#/Code-Behind file. This is a bit more cumbersome, but here's an example on how you may do it:

    <Window x:Class="WpfTutorialSamples.Basic_controls.TextBlockCodeBehindSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            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;
    		}
    	}
    }
    
    A TextBlock control with custom text formatting generated with C# code instead of XAML

    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.

    The Label control

    The Label control, in its most simple form, will look very much like the TextBlock which we used in another article. You will quickly notice though that instead of a Text property, the Label has a Content property. The reason 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:

    <Window x:Class="WpfTutorialSamples.Basic_controls.LabelControlSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="LabelControlSample" Height="100" Width="200">
        <Grid>
    		<Label Content="This is a Label control." />
    	</Grid>
    </Window>
    
    A simple Label control

    Another thing you might notice is the fact that the Label, by default, has a bit of padding, allowing the text to be rendered a few pixels away from the top, left corner. This is not the case for the TextBlock control, where you will have to specify it manually.

    In a simple case like this, where the content is simply a string, the Label will actually create a TextBlock internally and show your string in that.

    The Label control vs. the TextBlock control

    So why use a Label at all then? Well, there are a few important differences between the Label and the TextBlock. The TextBlock only allows you to render a text string, while the Label also allows you to:

    • Specify a border
    • Render other controls, e.g. an image
    • Use templated content through the ContentTemplate property
    • Use access keys to give focus to related controls

    The last bullet point is actually one of the main reasons for using a Label over the TextBlock control. Whenever you just want to render simple text, you should use the TextBlock control, since it's lighter and performs better than the Label in most cases.

    Label and Access keys (mnemonics)

    In Windows and other operating systems as well, it's common practice that you can access controls in a dialog by holding down the [Alt] key and then pressing a character which corresponds to the control that you wish to access. The character to press will be highlighted when you hold down the [Alt] key. TextBlock controls doesn't support this functionality, but the Label does, so for control labels, the Label control is usually an excellent choice. Let's look at an example of it in action:

    <Window x:Class="WpfTutorialSamples.Basic_controls.LabelControlSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="LabelControlSample" Height="180" Width="250">
    	<StackPanel Margin="10">
    		<Label Content="_Name:" Target="{Binding ElementName=txtName}" />
    		<TextBox Name="txtName" />
    		<Label Content="_Mail:" Target="{Binding ElementName=txtMail}" />
    		<TextBox Name="txtMail" />
    	</StackPanel>
    </Window>
    
    Label controls using access keys

    The screenshot shows our sample dialog as it looks when the Alt key is pressed. Try running it, holding down the [Alt] key and then pressing N and M. You will see how focus is moved between the two textboxes.

    So, there's several new concepts here. First of all, we define the access key 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 an access key for another control.

    We use the Target property to connect the Label and the designated control. We use a standard WPF binding for this, using the ElementName property, all of which we will describe later on in this tutorial. The binding is based on the name of the control, so if you change this name, you will also have to remember to change the binding.

    Using controls as Label content

    As already mentioned, the Label control allows you to host other controls, while still keeping the other benefits. Let's try an example where we have both an image and a piece of text inside the Label, while also having an access key for each of the labels:

    <Window x:Class="WpfTutorialSamples.Basic_controls.LabelControlAdvancedSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="LabelControlAdvancedSample" Height="180" Width="250">
    	<StackPanel Margin="10">
    		<Label Target="{Binding ElementName=txtName}">
    			<StackPanel Orientation="Horizontal">
    				<Image Source="http://cdn1.iconfinder.com/data/icons/fatcow/16/bullet_green.png" />
    				<AccessText Text="_Name:" />
    			</StackPanel>
    		</Label>
    		<TextBox Name="txtName" />
    		<Label Target="{Binding ElementName=txtMail}">
    			<StackPanel Orientation="Horizontal">
    				<Image Source="http://cdn1.iconfinder.com/data/icons/fatcow/16/bullet_blue.png" />
    				<AccessText Text="_Mail:" />
    			</StackPanel>
    		</Label>
    		<TextBox Name="txtMail" />
    	</StackPanel>
    </Window>
    
    Label controls using access keys

    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 label). Both controls are inside a horizontal StackPanel, since the Label, just like any other ContentControl derivate, can only host one direct child control.

    The Image control, described later in this tutorial, uses a remote image - this is ONLY for demonstrational purposes and is NOT a good idea for most real life applications.

    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.

    The TextBox control

    The TextBox control is the most basic text-input control found in WPF, allowing the end-user to write plain text, either on a single line, for dialog input, or in multiple lines, like an editor.

    Single-line TextBox

    The TextBox control is such a commonly used thing that you actually don't have to use any properties on it, to have a full-blown editable text field. Here's a barebone example:

    <Window x:Class="WpfTutorialSamples.Basic_controls.TextBoxSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="TextBoxSample" Height="80" Width="250">
        <StackPanel Margin="10">
    		<TextBox />
    	</StackPanel>
    </Window>
    

    A simple TextBox control

    That's all you need to get a text field. I added the text after running the sample and before taking the screenshot, but you can do it through markup as well, to pre-fill the textbox, using the Text property:

    <TextBox Text="Hello, world!" />
    

    Try right-clicking in the TextBox. You will get a menu of options, allowing you to use the TextBox with the Windows Clipboard. The default keyboard shortcuts for undoing and redoing (Ctrl+Z and Ctrl+Y) should also work, and all of this functionality you get for free!

    Multi-line TextBox

    If you run the above example, you will notice that the TextBox control by default is a single-line control. Nothing happens when you press Enter and if you add more text than what can fit on a single line, the control just scrolls. However, making the TextBox control into a multi-line editor is very simple:

    <Window x:Class="WpfTutorialSamples.Basic_controls.TextBoxSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="TextBoxSample" Height="160" Width="280">
        <Grid Margin="10">
    		<TextBox AcceptsReturn="True" TextWrapping="Wrap" />
    	</Grid>
    </Window>
    

    A TextBox control with multiple lines of text

    I have added two properties: The AcceptsReturn makes the TextBox into a 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.

    Spellcheck with TextBox

    As an added bonus, the TextBox control actually comes with automatic spell checking for English and a couple of other languages (as of writing, English, French, German, and Spanish languages are supported).

    It works much like in Microsoft Word, where spelling errors are underlined and you can right-click it for suggested alternatives. Enabling spell checking is very easy:

    <Window x:Class="WpfTutorialSamples.Basic_controls.TextBoxSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="TextBoxSample" Height="160" Width="280">
        <Grid Margin="10">
    		<TextBox AcceptsReturn="True" TextWrapping="Wrap" SpellCheck.IsEnabled="True" Language="en-US" />
    	</Grid>
    </Window>
    

    A TextBox control with automatic spell checking enabled

    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 class called IsEnabled, which simply enables spell checking on the parent control, and the Language property, which instructs the spell checker which language to use.

    Working with TextBox selections

    Just like any other editable control in Windows, the TextBox allows for selection of text, e.g. to delete an entire word at once or to copy a piece of the text to the clipboard. The WPF TextBox has several properties for working with selected text, all of them which you can read or even modify. In the next example, we will be reading these properties:

    <Window x:Class="WpfTutorialSamples.Basic_controls.TextBoxSelectionSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="TextBoxSelectionSample" Height="150" Width="300">
    	<DockPanel Margin="10">
    		<TextBox SelectionChanged="TextBox_SelectionChanged" DockPanel.Dock="Top" />
    		<TextBox Name="txtStatus" AcceptsReturn="True" TextWrapping="Wrap" IsReadOnly="True" />
    
    	</DockPanel>
    </Window>
    

    The example consists of two TextBox controls: One for editing and one for 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:

    using System;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    
    namespace WpfTutorialSamples.Basic_controls
    {
    	public partial class TextBoxSelectionSample : Window
    	{
    		public TextBoxSelectionSample()
    		{
    			InitializeComponent();
    		}
    
    		private void TextBox_SelectionChanged(object sender, RoutedEventArgs e)
    		{
    			TextBox textBox = sender as TextBox;
    			txtStatus.Text = "Selection starts at character #" + textBox.SelectionStart + Environment.NewLine;
    			txtStatus.Text += "Selection is " + textBox.SelectionLength + " character(s) long" + Environment.NewLine;
    			txtStatus.Text += "Selected text: '" + textBox.SelectedText + "'";
    		}
    	}
    }
    
    

    A TextBox control with selection status

    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.

    The CheckBox control

    The CheckBox control allows the end-user to toggle an option on or off, usually reflecting a Boolean value in the Code-behind. Let's jump straight into an example, in case you're not sure how a CheckBox looks:

    <Window x:Class="WpfTutorialSamples.Basic_controls.CheckBoxSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="CheckBoxSample" Height="140" Width="250">
        <StackPanel Margin="10">
    		<Label FontWeight="Bold">Application Options</Label>
    		<CheckBox>Enable feature ABC</CheckBox>
    		<CheckBox IsChecked="True">Enable feature XYZ</CheckBox>
    		<CheckBox>Enable feature WWW</CheckBox>
    	</StackPanel>
    </Window>
    
    

    A simple CheckBox control

    As you can see, the CheckBox is very easy to use. On the second CheckBox, I use the IsChecked property to have it checked by default, but other than that, no properties are needed to use it. The IsChecked property should also be used from Code-behind if you want to check whether a certain CheckBox is checked or not.

    Custom content

    The CheckBox control inherits from the ContentControl class, which means that it can take custom content and display next to it. If you just specify a piece of text, like I did in the example above, WPF will put it inside a TextBlock control and display it, but this is just a shortcut to make things easier for you. You can use any type of control inside of it, as we'll see in the next example:

    <Window x:Class="WpfTutorialSamples.Basic_controls.CheckBoxSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="CheckBoxSample" Height="140" Width="250">
        <StackPanel Margin="10">
    		<Label FontWeight="Bold">Application Options</Label>
    		<CheckBox>
    			<TextBlock>
    				Enable feature <Run Foreground="Green" FontWeight="Bold">ABC</Run>
    			</TextBlock>
    		</CheckBox>
    		<CheckBox IsChecked="True">
    			<WrapPanel>
    				<TextBlock>
    					Enable feature <Run FontWeight="Bold">XYZ</Run>
    				</TextBlock>
    				<Image Source="/WpfTutorialSamples;component/Images/question.png" Width="16" Height="16" Margin="5,0" />
    			</WrapPanel>
    		</CheckBox>
    		<CheckBox>
    			<TextBlock>
    				Enable feature <Run Foreground="Blue" TextDecorations="Underline" FontWeight="Bold">WWW</Run>
    			</TextBlock>
    		</CheckBox>
    	</StackPanel>
    </Window>
    

    A CheckBox control with custom content

    As you can see from the sample markup, you can do pretty much whatever you want with the content. On all three check boxes, I do something differently with the text, and on the middle one I even throw in an Image control. By specifying a control as the content, instead of just text, we get 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.

    The IsThreeState property

    As mentioned, the CheckBox usually corresponds to a boolean value, which means that it only has two states: true or false (on or off). However, since a boolean data type might be nullable, effectively allowing for a third option (true, false or null), the CheckBox control can also support this case. By 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 control a set of child checkboxes, as well as show their collective state. Our example shows how you may create a list of features that can be toggled on and off, with a common "Enable all" CheckBox in the top:

    <Window x:Class="WpfTutorialSamples.Basic_controls.CheckBoxThreeStateSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="CheckBoxThreeStateSample" Height="170" Width="300">
    	<StackPanel Margin="10">
    		<Label FontWeight="Bold">Application Options</Label>
    		<StackPanel Margin="10,5">
    			<CheckBox IsThreeState="True" Name="cbAllFeatures" Checked="cbAllFeatures_CheckedChanged"
                 Unchecked="cbAllFeatures_CheckedChanged">Enable all</CheckBox>
    			<StackPanel Margin="20,5">
    				<CheckBox Name="cbFeatureAbc" Checked="cbFeature_CheckedChanged" 
                    Unchecked="cbFeature_CheckedChanged">Enable feature ABC</CheckBox>
    				<CheckBox Name="cbFeatureXyz" IsChecked="True" Checked="cbFeature_CheckedChanged" 
                    Unchecked="cbFeature_CheckedChanged">Enable feature XYZ</CheckBox>
    				<CheckBox Name="cbFeatureWww" Checked="cbFeature_CheckedChanged" 
                    Unchecked="cbFeature_CheckedChanged">Enable feature WWW</CheckBox>
    			</StackPanel>
    		</StackPanel>
    	</StackPanel>
    </Window>
    
    
    using System;
    using System.Windows;
    
    namespace WpfTutorialSamples.Basic_controls
    {
    	public partial class CheckBoxThreeStateSample : Window
    	{
    		public CheckBoxThreeStateSample()
    		{
    			InitializeComponent();
    		}
    
    
    		private void cbAllFeatures_CheckedChanged(object sender, RoutedEventArgs e)
    		{
    			bool newVal = (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 == true) && (cbFeatureXyz.IsChecked == true) && (cbFeatureWww.IsChecked == true))
    				cbAllFeatures.IsChecked = true;
    			if((cbFeatureAbc.IsChecked == false) && (cbFeatureXyz.IsChecked == false) && (cbFeatureWww.IsChecked == false))
    				cbAllFeatures.IsChecked = false;
    		}
    
    	}
    }
    

    A three state CheckBox control in the inderminate state A three state CheckBox control in the checked state A three state CheckBox control in the unchecked state

    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.

    The RadioButton control

    The RadioButton control allows you to give your user a list of possible options, with only one of them selected at the same time. You can achieve the same effect, using less space, with the ComboBox control, but a set of radio buttons tend to give the user a better overview of the options they have.

    <Window x:Class="WpfTutorialSamples.Basic_controls.RadioButtonSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="RadioButtonSample" Height="150" Width="250">
    	<StackPanel Margin="10">
    		<Label FontWeight="Bold">Are you ready?</Label>
    		<RadioButton>Yes</RadioButton>
    		<RadioButton>No</RadioButton>
    		<RadioButton IsChecked="True">Maybe</RadioButton>
    	</StackPanel>
    </Window>
    
    

    A simple RadioButton control

    All we do is add a Label with a question, and then three radio buttons, each with a possible answer. We define a default option by using the IsChecked property on the last RadioButton, which the user can change simply by clicking on one of the other radio buttons. This is also the property you would want to use from Code-behind to check if a RadioButton is checked or not.

    RadioButton groups

    If you try running the example above, you will see that, as promised, only one RadioButton can be checked at the same time. But what if you want several groups of radio buttons, each with their own, individual selection? This is what the GroupName property comes into play, which allows you to specify which radio buttons belong together. Here's an example:

    <Window x:Class="WpfTutorialSamples.Basic_controls.RadioButtonSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="RadioButtonSample" Height="230" Width="250">
    	<StackPanel Margin="10">
    		<Label FontWeight="Bold">Are you ready?</Label>
    		<RadioButton GroupName="ready">Yes</RadioButton>
    		<RadioButton GroupName="ready">No</RadioButton>
    		<RadioButton GroupName="ready" IsChecked="True">Maybe</RadioButton>
    
    		<Label FontWeight="Bold">Male or female?</Label>
    		<RadioButton GroupName="sex">Male</RadioButton>
    		<RadioButton GroupName="sex">Female</RadioButton>
    		<RadioButton GroupName="sex" IsChecked="True">Not sure</RadioButton>
    	</StackPanel>
    </Window>
    

    Two groups of radio buttons using the GroupName property

    With the GroupName property set on each of the radio buttons, a selection can now be made for each of the two groups. Without this, only one selection for all six radio buttons would be possible.

    Custom content

    The RadioButton inherits from the ContentControl class, which means that it can take custom content and display next to it. If you just specify a piece of text, like I did in the example above, WPF will put it inside a TextBlock control and display it, but this is just a shortcut to make things easier for you. You can use any type of control inside of it, as we'll see in the next example:

    <Window x:Class="WpfTutorialSamples.Basic_controls.RadioButtonCustomContentSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="RadioButtonCustomContentSample" Height="150" Width="250">
    	<StackPanel Margin="10">
    		<Label FontWeight="Bold">Are you ready?</Label>
    		<RadioButton>
    			<WrapPanel>
    				<Image Source="/WpfTutorialSamples;component/Images/accept.png"
                     Width="16" Height="16" Margin="0,0,5,0" />
    				<TextBlock Text="Yes" Foreground="Green" />
    			</WrapPanel>
    		</RadioButton>
    		<RadioButton Margin="0,5">
    			<WrapPanel>
    				<Image Source="/WpfTutorialSamples;component/Images/cancel.png"
                     Width="16" Height="16" Margin="0,0,5,0" />
    				<TextBlock Text="No" Foreground="Red" />
    			</WrapPanel>
    		</RadioButton>
    		<RadioButton IsChecked="True">
    			<WrapPanel>
    				<Image Source="/WpfTutorialSamples;component/Images/question.png" 
                    Width="16" Height="16" Margin="0,0,5,0" />
    				<TextBlock Text="Maybe" Foreground="Gray" />
    			</WrapPanel>
    		</RadioButton>
    	</StackPanel>
    </Window>
    

    Radio buttons with custom content

    Markup-wise, this example gets a bit heavy, but the concept is pretty simple. 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 (read more about those later) is used to display an image for each choice.

    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 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 RadioButton to activate it, which is less practical.

    The PasswordBox control

    For editing regular text in WPF we have the TextBox, but what about editing passwords? The functionality is very much the same, but we want WPF to display something else than the actual characters when typing in a password, 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:

    <Window x:Class="WpfTutorialSamples.Basic_controls.PasswordBoxSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="PasswordBoxSample" Height="160" Width="300">
        <StackPanel Margin="10">
            <Label>Text:</Label>
            <TextBox />
            <Label>Password:</Label>
            <PasswordBox />
        </StackPanel>
    </Window>
    

    A simple PasswordBox control

    In the screenshot, I have entered the exact same text into the two text boxes, but in the password version, the characters are replaced with dots. You can actually control which character is used instead of the real characters, using the PasswordChar property:

    <PasswordBox PasswordChar="X" />
    

    In this case, the character X will be used instead of the dots. In case you need to control the length of the password, there's a MaxLength property for you:

    <PasswordBox MaxLength="6" />
    

    I have used both properties in this updated example:

    <Window x:Class="WpfTutorialSamples.Basic_controls.PasswordBoxSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="PasswordBoxSample" Height="160" Width="300">
        <StackPanel Margin="10">
            <Label>Text:</Label>
            <TextBox />
            <Label>Password:</Label>
            <PasswordBox MaxLength="6" PasswordChar="X" />
        </StackPanel>
    </Window>
    

    A simple PasswordBox control, with a couple of extra properties set

    Notice how the characters are now X's instead, and that I was only allowed to enter 6 characters in the box.

    PasswordBox and binding

    When you need to obtain the password from the PasswordBox, you can use the Password property from Code-behind. However, for security reasons, the Password property is not implemented as a dependency property, which means that you can't bind to it.

    This may or may not be important to you - as already stated, you can still read the password from Code-behind, but for MVVM implementations or if you just love data bindings, a workaround has been developed. You can read much more about it here: http://blog.functionalfun.net/2008/06/wpf-passwordbox-and-data-binding.html

    advertise here!!!
  • Control concepts ↓

    advertise here!!!

    Control ToolTips

    Tooltips, infotips or hints - various names, but the concept remains the same: The ability to get extra information about a specific control or link by hovering the mouse over it. WPF obviously supports this concept as well, and by using the ToolTip property found on the FrameworkElement class, which almost any WPF control inherits from.

    Specifying a tooltip for a control is very easy, as you will see in this first and very basic example:

    <Window x:Class="WpfTutorialSamples.Control_concepts.ToolTipsSimpleSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="ToolTipsSimpleSample" Height="150" Width="400">
        <Grid VerticalAlignment="Center" HorizontalAlignment="Center">
    
            <Button ToolTip="Click here and something will happen!">Click here!</Button>
    
        </Grid>
    </Window>
    

    A simple ToolTip example

    As you can see on the screenshots, this results in a floating box with the specified string, once the mouse hovers over the button. This is what most UI frameworks offers - the display of a text string and nothing more.

    However, in WPF, the ToolTip property is actually not a string type, but instead an object type, meaning that we can put whatever we want in there. This opens up for some pretty cool possibilities, where we can provide the user with much richer and more helpful tooltips. For instance, consider this example and compare it to the first one:

    <Window x:Class="WpfTutorialSamples.Control_concepts.ToolTipsAdvancedSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="ToolTipsAdvancedSample" Height="200" Width="400" UseLayoutRounding="True">
        <DockPanel>
            <ToolBar DockPanel.Dock="Top">
                <Button ToolTip="Create a new file">
                    <Button.Content>
                        <Image Source="/WpfTutorialSamples;component/Images/page_white.png" Width="16" Height="16" />
                    </Button.Content>
                </Button>
                <Button>
                    <Button.Content>
                        <Image Source="/WpfTutorialSamples;component/Images/folder.png" Width="16" Height="16" />
                    </Button.Content>
                    <Button.ToolTip>
                        <StackPanel>
                            <TextBlock FontWeight="Bold" FontSize="14" Margin="0,0,0,5">Open file</TextBlock>
                            <TextBlock>
                            Search your computer or local network
                            <LineBreak />
                            for a file and open it for editing.
                            </TextBlock>
                            <Border BorderBrush="Silver" BorderThickness="0,1,0,0" Margin="0,8" />
                            <WrapPanel>
                                <Image Source="/WpfTutorialSamples;component/Images/help.png" Margin="0,0,5,0" />
                                <TextBlock FontStyle="Italic">Press F1 for more help</TextBlock>
                            </WrapPanel>
                        </StackPanel>
                    </Button.ToolTip>
                </Button>
            </ToolBar>
    
            <TextBox>
                Editor area...
            </TextBox>
        </DockPanel>
    </Window>
    

    A more advanced ToolTip example

    Notice how this example uses a simple string tooltip for the first button and then a much more advanced one for the second button. In the advanced case, we use a panel as the root control and then we're free to add controls to that as we please. The result is pretty cool, with a header, a description text and a hint that you can press F1 for more help, including a help icon.

    Advanced options

    The ToolTipService class has a bunch of interesting properties that will affect the behavior of your tooltips. You set them directly on the control that has the tooltip, for instance like here, where we extend the time a tooltip is shown using the ShowDuration property (we set it to 5.000 milliseconds or 5 seconds):

        <Button ToolTip="Create a new file" ToolTipService.ShowDuration="5000" Content="Open" />
    

    You can also control whether or not the popup should have a shadow, using the HasDropShadow property, or whether tooltips should be displayed for disabled controls as well, using the ShowOnDisabled property. There are several other interesting properties, so for a complete list, please consult the documentation: http://msdn.microsoft.com/en-us/library/system.windows.controls.tooltipservice.aspx

    Summary

    Tooltips can be a great help for the user, and in WPF, they are both easy to use and extremely flexible. Combine the fact that you can completely control the design and content of the tooltip, with properties from the ToolTipService class, to create more user friendly inline help in your applications.

    WPF text rendering

    In this article, we'll be discussing why text is sometimes rendered more blurry with WPF, how this was later fixed and how you can control text rendering yourself.

    As already mentioned in this tutorial, WPF does a lot more things on its own when compared to other UI frameworks like WinForms, which will use the Windows API for many, many things. This is also clear when it comes to the rendering of text - WinForms uses the GDI API from Windows, while WPF has its own text rendering implementation, to better support animations as well as the device independent nature of WPF.

    Unfortunately, this led to text being rendered a bit blurry, especially in small font sizes. This was a rather big problem for WPF programmers for some time, but luckily, Microsoft made a lot of improvements in the WPF text rendering engine in .NET framework version 4.0. This means that if you're using this version or higher, your text should be almost as good as pixel perfect.

    Controlling text rendering

    With .NET framework 4.0, Microsoft also decided to give more control of text rendering to the programmer, by introducing the TextOptions class with the TextFormattingMode and TextRenderingMode properties. This allows you to specifically decide how text should be formatted and rendered on a control level. This is probably best illustrated with an example, so have a look at the code and the screenshots below to see how you can affect text rendering with these properties.

    TextFormattingMode

    Using the TextFormattingMode property, you get to decide which algorithm should be used when formatting the text. You can choose between Ideal (the default value) and Display. You would normally want to leave this property untouched, since the Ideal setting will be best for most situations, but in cases where you need to render very small text, the Display setting can sometimes yield a better result. Here's an example where you can see the difference (although it's very subtle):

    <Window x:Class="WpfTutorialSamples.Control_concepts.TextFormattingModeSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="TextFormattingModeSample" Height="200" Width="400">
        <StackPanel Margin="10">
            <Label TextOptions.TextFormattingMode="Ideal" FontSize="9">TextFormattingMode.Ideal, small text</Label>
            <Label TextOptions.TextFormattingMode="Display" FontSize="9">TextFormattingMode.Display, small text</Label>
            <Label TextOptions.TextFormattingMode="Ideal" FontSize="20">TextFormattingMode.Ideal, large text</Label>
            <Label TextOptions.TextFormattingMode="Display" FontSize="20">TextFormattingMode.Display, large text</Label>
        </StackPanel>
    </Window>
    

    Using the TextFormattingMode property

    TextRenderingMode

    The TextRenderingMode property gives you control of which antialiasing algorithm is used when rendering text. It has the biggest effect in combination with the Display setting for the TextFormattingMode property, which we'll use in this example to illustrate the differences:

    <Window x:Class="WpfTutorialSamples.Control_concepts.TextRenderingModeSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="TextRenderingModeSample" Height="300" Width="400">
        <StackPanel Margin="10" TextOptions.TextFormattingMode="Display">
            <Label TextOptions.TextRenderingMode="Auto" FontSize="9">TextRenderingMode.Auto, small text</Label>
            <Label TextOptions.TextRenderingMode="Aliased" FontSize="9">TextRenderingMode.Aliased, small text</Label>
            <Label TextOptions.TextRenderingMode="ClearType" FontSize="9">TextRenderingMode.ClearType, small text</Label>
            <Label TextOptions.TextRenderingMode="Grayscale" FontSize="9">TextRenderingMode.Grayscale, small text</Label>
            <Label TextOptions.TextRenderingMode="Auto" FontSize="18">TextRenderingMode.Auto, large text</Label>
            <Label TextOptions.TextRenderingMode="Aliased" FontSize="18">TextRenderingMode.Aliased, large text</Label>
            <Label TextOptions.TextRenderingMode="ClearType" FontSize="18">TextRenderingMode.ClearType, large text</Label>
            <Label TextOptions.TextRenderingMode="Grayscale" FontSize="18">TextRenderingMode.Grayscale, large text</Label>
        </StackPanel>
    </Window>
    

    Using the TextRenderingMode property

    As you can see, the resulting text differs quite a bit in how it looks and once again, you should mainly change this in special circumstances.

    advertise here!!!
  • Panels in WPF ↓

    Introduction to WPF panels

    advertise here!!!

    Panels are one of the most important control types of WPF. They act as containers for other controls and control the layout of your windows/pages. Since a window can only contain ONE child control, a panel is often used to 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 of dealing with layout and child controls. Picking the right panel is therefore essential to getting the behavior and layout you want, and especially in the 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 described in detail.

    Canvas

    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 to manually move the child controls around and make sure that they align the way you want them to. Use it (only) when you want complete control of the child control positions.

    WrapPanel

    The WrapPanel will position each of its child controls next to the other, horizontally (default) or vertically, until there is no more room, where it will wrap to the next line and then continue. Use it when you want a vertical or horizontal list controls that automatically wraps when there's no more room.

    StackPanel

    The StackPanel acts much like the WrapPanel, but instead of wrapping if the child controls take up too much room, it simply expands itself, if possible. Just like with the WrapPanel, the orientation can be either horizontal or vertical, but instead of adjusting the width or height of the child controls based on the largest item, each item is stretched to take up the full width or height. Use the StackPanel when you want a list of controls that takes up all the available room, without wrapping.

    DockPanel

    The DockPanel allows you to dock the child controls to the top, bottom, left or right. By default, the last control, if not given a specific dock position, will fill the remaining space. You can achieve the same with the Grid panel, but for the simpler situations, the DockPanel will be easier to use. Use the DockPanel whenever you need to dock one or several controls to one of the sides, like for dividing up the window into specific areas.

    Grid

    The Grid is probably the most complex of the panel types. A Grid can contain multiple rows and columns. You define a height for each of the rows and a width for each of the columns, in either an absolute amount of pixels, in a 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.

    UniformGrid

    The UniformGrid is just like the Grid, with the possibility of multiple rows and columns, but with one important difference: All rows and columns will have the same size! Use this when you need the Grid behavior without the need to specify different sizes for the rows and columns.

    Canvas control

    The Canvas is probably the simplest Panel of them all. It doesn't really do anything by default, it just allows you to put controls in it and then position them yourself using explicit coordinates.

    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 anything for you once the user starts resizing your window, if you localize absolutely positioned text or if the content is scaled.

    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:

    <Window x:Class="WpfTutorialSamples.Panels.Canvas"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="Canvas" Height="200" Width="200">
    	<Canvas>
    		<Button>Button 1</Button>
    		<Button>Button 2</Button>
    	</Canvas>
    </Window>
    

    A simple Canvas

    As you can see, even though we have two buttons, they are both placed in the exact same place, so only the last one is visible. The Canvas does absolutely nothing until you start giving coordinates to the child controls. This is done using the Left, Right, Top and Bottom attached properties from the Canvas control.

    These properties allow you to specify the position relative to the four edges of the Canvas. By default, they are all set to NaN (Not a Number), which will make the Canvas place them in the upper left corner, but as mentioned, you can easily change this:

    <Window x:Class="WpfTutorialSamples.Panels.Canvas"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="Canvas" Height="200" Width="200">
    	<Canvas>
    		<Button Canvas.Left="10">Top left</Button>
    		<Button Canvas.Right="10">Top right</Button>
    		<Button Canvas.Left="10" Canvas.Bottom="10">Bottom left</Button>
    		<Button Canvas.Right="10" Canvas.Bottom="10">Bottom right</Button>
    	</Canvas>
    </Window>
    

    A simple Canvas, where we position the child elements

    Notice how I only set the property or properties that I need. For the first two buttons, I only wish to specify a value for the X axis, so I use the Left and 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 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.

    As mentioned, since the Canvas gives you complete control of positions, it won't really care whether or not there's enough room for all your controls or if one is on top of another. This makes it a bad choice for pretty much any kind of dialog design, but the Canvas is, as the name implies, great for at least one thing: Painting. WPF has a bunch of controls that you can place inside a Canvas, to make nice illustrations.

    Z-Index

    In the next example, we'll use a couple of the shape related controls of WPF to illustrate another very important concept when using the Canvas: Z-Index. Normally, if two controls within a Canvas overlaps, the one defined last in the 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:

    <Window x:Class="WpfTutorialSamples.Panels.CanvasZIndex"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="CanvasZIndex" Height="275" Width="260">
        <Canvas>
            <Ellipse Fill="Gainsboro" Canvas.Left="25" Canvas.Top="25" Width="200" Height="200" />
            <Rectangle Fill="LightBlue" Canvas.Left="25" Canvas.Top="25" Width="50" Height="50" />
            <Rectangle Fill="LightCoral" Canvas.Left="50" Canvas.Top="50" Width="50" Height="50" />
            <Rectangle Fill="LightCyan" Canvas.Left="75" Canvas.Top="75" Width="50" Height="50" />
        </Canvas>
    </Window>
    

    A Canvas with overlapping elements, not using the ZIndex property

    Notice that because each of the rectangles are defined after the circle, they all overlap the circle, and each of them will overlap the previously defined one. Let's try changing that:

    <Window x:Class="WpfTutorialSamples.Panels.CanvasZIndex"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="CanvasZIndex" Height="275" Width="260">
        <Canvas>
            <Ellipse Panel.ZIndex="2" Fill="Gainsboro" Canvas.Left="25" Canvas.Top="25" Width="200" Height="200" />
            <Rectangle Panel.ZIndex="3" Fill="LightBlue" Canvas.Left="25" Canvas.Top="25" Width="50" Height="50" />
            <Rectangle Panel.ZIndex="2" Fill="LightCoral" Canvas.Left="50" Canvas.Top="50" Width="50" Height="50" />
            <Rectangle Panel.ZIndex="4" Fill="LightCyan" Canvas.Left="75" Canvas.Top="75" Width="50" Height="50" />
        </Canvas>
    </Window>
    

    A Canvas with overlapping elements, using the ZIndex property

    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.



    WrapPanel control

    The WrapPanel will position each of its child controls next to the other, horizontally (default) or vertically, until there is no more room, where it will wrap to the next line and then continue. Use it when you want a vertical or 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 Vertical orientation, the child controls will be given the same width, based on the widest item.

    In the first example, we'll check out a WrapPanel with the default (Horizontal) orientation:

    <Window x:Class="WpfTutorialSamples.Panels.WrapPanel"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="WrapPanel" Height="300" Width="300">
    	<WrapPanel>
    		<Button>Test button 1</Button>
    		<Button>Test button 2</Button>
    		<Button>Test button 3</Button>
    		<Button Height="40">Test button 4</Button>
    		<Button>Test button 5</Button>
    		<Button>Test button 6</Button>
    	</WrapPanel>
    </Window>
    
    WrapPanel in Horizontal mode

    Notice how I set a specific height on one of the buttons in the second row. In the resulting screenshot, you will see that this causes the entire row of buttons to have the same height instead of the height required, as seen on the first row. You will also notice that the panel does exactly what the name implies: It wraps the content when it can't fit any more of it in. In this case, the fourth button couldn't fit in on the first line, so it automatically wraps to the next line.

    Should you make the window, and thereby the available space, smaller, you will see how the panel immediately adjusts to it:

    WrapPanel in Horizontal mode

    All of this behavior is also true when you set the Orientation to Vertical. Here's the exact same example as before, but with a Vertical WrapPanel:

    <Window x:Class="WpfTutorialSamples.Panels.WrapPanel"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="WrapPanel" Height="120" Width="300">
    	<WrapPanel Orientation="Vertical">
    		<Button>Test button 1</Button>
    		<Button>Test button 2</Button>
    		<Button>Test button 3</Button>
    		<Button Width="140">Test button 4</Button>
    		<Button>Test button 5</Button>
    		<Button>Test button 6</Button>
    	</WrapPanel>
    </Window>
    
    WrapPanel in Vertical mode

    You can see how the buttons go vertical instead of horizontal, before they wrap because they reach the bottom of the window. In this case, I gave a wider width to the fourth button, and you will see that the buttons in the same column also gets the same width, just like we saw with the button height in the Horizontal example.

    Please be aware that while the Horizontal WrapPanel will match the height in the same row and the Vertical WrapPanel will match the width in the same column, height is not matched in a Vertical WrapPanel and width is not matched in a Horizontal WrapPanel. Take a look in this example, which is the Vertical WrapPanel but where the fourth button gets a custom width AND height:

    <Button Width="140" Height="44">Test button 4</Button>
    

    It will look like this:

    WrapPanel in Vertical mode with specific width/heights

    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.



    StackPanel control

    A simple StackPanel in Vertical mode

    The first thing you should notice is how the StackPanel doesn't really care whether or not there's enough room for the content. It doesn't wrap the content in any way and it doesn't automatically provide you with the ability to scroll (you can use a ScrollViewer control for that though - more on that in a later chapter).

    You might also notice that the default orientation of the StackPanel is Vertical, unlike the WrapPanel where the default orientation is Horizontal. But just like for the WrapPanel, this can easily be changed, using the Orientation property:

    <StackPanel Orientation="Horizontal">
    

    A simple StackPanel in Horizontal mode

    Another thing you will likely notice is that the StackPanel stretches its child control by default. On a vertically aligned StackPanel, like the one in the first example, all child controls get stretched horizontally. On a horizontally aligned StackPanel, all child controls get stretched vertically, as seen above. The StackPanel does this by setting the HorizontalAlignment or VerticalAlignment property on its child controls to Stretch, but you can easily override this if you want to. Have a look at the next example, where we use the same markup as we did in the previous example, but this time we assign values to the VerticalAlignment property for all the child controls:

    <Window x:Class="WpfTutorialSamples.Panels.StackPanel"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="StackPanel" Height="160" Width="300">
    	<StackPanel Orientation="Horizontal">
    		<Button VerticalAlignment="Top">Button 1</Button>
    		<Button VerticalAlignment="Center">Button 2</Button>
    		<Button VerticalAlignment="Bottom">Button 3</Button>
    		<Button VerticalAlignment="Bottom">Button 4</Button>
    		<Button VerticalAlignment="Center">Button 5</Button>
    		<Button VerticalAlignment="Top">Button 6</Button>
    	</StackPanel>
    </Window>
    

    A StackPanel in Vertical mode with differently aligned controls

    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 child controls:

    <Window x:Class="WpfTutorialSamples.Panels.StackPanel"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="StackPanel" Height="160" Width="300">
    	<StackPanel Orientation="Vertical">
    		<Button HorizontalAlignment="Left">Button 1</Button>
    		<Button HorizontalAlignment="Center">Button 2</Button>
    		<Button HorizontalAlignment="Right">Button 3</Button>
    		<Button HorizontalAlignment="Right">Button 4</Button>
    		<Button HorizontalAlignment="Center">Button 5</Button>
    		<Button HorizontalAlignment="Left">Button 6</Button>
    	</StackPanel>
    </Window>
    

    A StackPanel in Horizontal mode with differently aligned controls

    As you can see, the controls still go from top to bottom, but instead of having the same width, each control is aligned to the left, the right or center.



    DockPanel control

    The DockPanel makes it easy to dock content in all four directions (top, bottom, left and right). This makes it a great choice in many situations, where you want to divide the window into specific areas, especially because by 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 advantage of the panel possibilities by using an attached property of it, in this case the DockPanel.Dock property, which decides in which direction you 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:

    <Window x:Class="WpfTutorialSamples.Panels.DockPanel"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="DockPanel" Height="250" Width="250">
    	<DockPanel>
    		<Button DockPanel.Dock="Left">Left</Button>
    		<Button DockPanel.Dock="Top">Top</Button>
    		<Button DockPanel.Dock="Right">Right</Button>
    		<Button DockPanel.Dock="Bottom">Bottom</Button>
    		<Button>Center</Button>
    	</DockPanel>
    </Window>
    
    A simple DockPanel

    As already mentioned, we don't assign a dock position for the last child, because it automatically centers the control, allowing it to fill the remaining space. You will also notice that the controls around the center only takes up the amount of space that they need - everything else is left for the center 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.

    The last thing that you will likely notice, is how the space is divided. For instance, the Top button doesn't get all of the top space, because the Left button takes a part of it. The DockPanel decides which control to favor by looking at their position in the markup. In this case, the Left button gets precedence because it's placed first in the markup. Fortunately, this also means that it's very easy to change, as we'll see in the next example, where we have also evened out the space a bit by assigning widths/heights to the child controls:

    <Window x:Class="WpfTutorialSamples.Panels.DockPanel"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="DockPanel" Height="250" Width="250">
    	<DockPanel>
    		<Button DockPanel.Dock="Top" Height="50">Top</Button>
    		<Button DockPanel.Dock="Bottom" Height="50">Bottom</Button>
    		<Button DockPanel.Dock="Left" Width="50">Left</Button>
    		<Button DockPanel.Dock="Right" Width="50">Right</Button>	
    		<Button>Center</Button>
    	</DockPanel>
    </Window>
    
    A DockPanel where width or heights has been specified for the child controls

    The top and bottom controls now take precedence over the left and right controls, and they're all taking up 50 pixels in either height or width. If you make the window bigger or smaller, you will also see that this static width/height remains the same no matter what - only the center area increases or decreases in size as you resize the window.

    LastChildFill

    As already mentioned, the default behavior is that the last child of the DockPanel takes up the rest of the space, but this can be disabled using the LastChildFill. Here's an example where we disable it, and at the same time we'll show the ability to dock more than one control to the same side:

    <Window x:Class="WpfTutorialSamples.Panels.DockPanel"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="DockPanel" Height="300" Width="300">
    	<DockPanel LastChildFill="False">
    		<Button DockPanel.Dock="Top" Height="50">Top</Button>
    		<Button DockPanel.Dock="Bottom" Height="50">Bottom</Button>
    		<Button DockPanel.Dock="Left" Width="50">Left</Button>
    		<Button DockPanel.Dock="Left" Width="50">Left</Button>
    		<Button DockPanel.Dock="Right" Width="50">Right</Button>
    		<Button DockPanel.Dock="Right" Width="50">Right</Button>
    	</DockPanel>
    </Window>
    
    A DockPanel where the LastChildFill property has been disabled

    In this example, we dock two controls to the left and two controls to the right, and at the same time, we turn off the LastChildFill property. This leaves us with empty space in the center, which may be preferable in some cases.



    Grid Control

    The Grid is probably the most complex of the panel types. A Grid can contain multiple rows and columns. You define a height for each of the rows and a width for each of the columns, in either an absolute amount of pixels, in a 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.

    In its most basic form, the Grid will simply take all of the controls you put into it, stretch them to use the maximum available space and place it on top of each other:

    <Window x:Class="WpfTutorialSamples.Panels.Grid"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="Grid" Height="300" Width="300">
        <Grid>
    		<Button>Button 1</Button>
    		<Button>Button 2</Button>
    	</Grid>
    </Window>
    
    A simple Grid

    As you can see, the last control gets the top position, which in this case means that you can't even see the first button. Not terribly useful for most situations though, so let's try dividing the space, which is what the grid does so well. We do that by using ColumnDefinitions and RowDefinitions. In the first example, we'll stick to columns:

    <Window x:Class="WpfTutorialSamples.Panels.Grid"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="Grid" Height="300" Width="300">
        <Grid>
    		<Grid.ColumnDefinitions>
    			<ColumnDefinition Width="*" />
    			<ColumnDefinition Width="*" />
    		</Grid.ColumnDefinitions>
    		<Button>Button 1</Button>
    		<Button Grid.Column="1">Button 2</Button>
    	</Grid>
    </Window>
    
    A Grid divided into two columns

    In this example, we have simply divided the available space into two columns, which will share the space equally, using a "star width" (this will be explained later). On the second button, I use a so-called Attached property to place the button in the second column (0 is the first column, 1 is the second and so on). I could have used this property on the first button as well, but it automatically gets assigned to the first column and the first row, which is exactly what we want here.

    As you can see, the controls take up all the available space, which is the default behavior when the grid arranges its child controls. It does this by setting the HorizontalAlignment and VerticalAlignment on its child controls to Stretch.

    In some situations you may want them to only take up the space they need though and/or control how they are placed in the Grid. The easiest way to do this is to set the HorizontalAlignment and VerticalAlignment directly on the controls you wish to manipulate. Here's a modified version of the above example:

    <Window x:Class="WpfTutorialSamples.Panels.Grid"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="Grid" Height="300" Width="300">
        <Grid>
    		<Grid.ColumnDefinitions>
    			<ColumnDefinition Width="*" />
    			<ColumnDefinition Width="*" />
    		</Grid.ColumnDefinitions>		
    		<Button VerticalAlignment="Top" HorizontalAlignment="Center">Button 1</Button>
    		<Button Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Right">Button 2</Button>
    	</Grid>
    </Window>
    
    A Grid divided into two columns with custom alignment on the child controls

    As you can see from the resulting screenshot, the first button is now placed in the top and centered. The second button is placed in the middle, aligned to the right.



    Grid - Rows & columns

    In the last chapter, we introduced you to the great Grid panel and showed you a couple of basic examples on how to use it. In this chapter we will do some more advanced layouts, as this is where the Grid really shines. First of all, let's throw in more columns and even some rows, for a true tabular layout:

    <Window x:Class="WpfTutorialSamples.Panels.TabularGrid"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="TabularGrid" Height="300" Width="300">
        <Grid>
    		<Grid.ColumnDefinitions>
    			<ColumnDefinition Width="2*" />
    			<ColumnDefinition Width="1*" />
    			<ColumnDefinition Width="1*" />
    		</Grid.ColumnDefinitions>
    		<Grid.RowDefinitions>
    			<RowDefinition Height="2*" />
    			<RowDefinition Height="1*" />
    			<RowDefinition Height="1*" />
    		</Grid.RowDefinitions>
    		<Button>Button 1</Button>
    		<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" Grid.Row="1">Button 5</Button>
    		<Button Grid.Column="2" Grid.Row="1">Button 6</Button>
    		<Button Grid.Row="2">Button 7</Button>
    		<Button Grid.Column="1" Grid.Row="2">Button 8</Button>
    		<Button Grid.Column="2" Grid.Row="2">Button 9</Button>
    	</Grid>
    </Window>
    
    A Grid with several columns and rows, creating a tabular layout

    A total of nine buttons, each placed in their own cell in a grid containing three rows and three columns. We once again use a star based width, but this time we assign a number as well - the first row and the first column has a width of 2*, which basically means that it uses twice the amount of space as the rows and columns with a width of 1* (or just * - that's the same).

    You will also notice that I use the Attached properties Grid.Row and Grid.Column to place the controls in the grid, and once again you will notice 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 them anyway for a better overview - that's totally up to you!



    Grid - Units

    So far we have mostly used the star width/height, which specifies that a row or a column should take up a certain percentage of the combined space. However, there are two other ways of specifying the width or height of a column or a row: Absolute units and the Auto width/height. Let's try creating a Grid where we mix these:

    <Window x:Class="WpfTutorialSamples.Panels.GridUnits"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="GridUnits" Height="200" Width="400">
    	<Grid>
    		<Grid.ColumnDefinitions>
    			<ColumnDefinition Width="1*" />
    			<ColumnDefinition Width="Auto" />
    			<ColumnDefinition Width="100" />
    		</Grid.ColumnDefinitions>
    		<Button>Button 1</Button>
    		<Button Grid.Column="1">Button 2 with long text</Button>
    		<Button Grid.Column="2">Button 3</Button>
    	</Grid>
    </Window>
    
    A Grid with columns of varying widths

    In this example, the first button has a star width, the second one has its width set to Auto and the last one has a static width of 100 pixels.

    The result can be seen on the screenshot, where the second button only takes exactly the amount of space it needs to render its longer text, the third button takes exactly the 100 pixels it was promised and the first button, with the variable width, takes the rest.

    In a Grid where one or several columns (or rows) have a variable (star) width, they automatically get to share the width/height not already used by the columns/rows which uses an absolute or Auto width/height. This becomes more obvious when we resize the window:

    A Grid with columns of varying widths, resized to a smaller size A Grid with columns of varying widths, resized to a larger size

    On the first screenshot, you will see that the Grid reserves the space for the 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 surplus space to the first button.

    This can be a very useful technique when designing a wide range of dialogs. For instance, consider a simple contact form where the user enters a name, an e-mail address and a comment. The first two fields will usually have a fixed height, while the last one might as well take up as much space as 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.



    Grid - Spanning

    The default Grid behavior is that each control takes up one cell, but sometimes you want a certain control to take up more rows or columns. Fortunately the Grid makes this very easy, with the Attached properties 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.

    Here's a very simple example, where we use the ColumnSpan property:

    <Window x:Class="WpfTutorialSamples.Panels.GridColRowSpan"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="GridColRowSpan" Height="110" Width="300">
    	<Grid>
    		<Grid.ColumnDefinitions>			
    			<ColumnDefinition Width="1*" />
    			<ColumnDefinition Width="1*" />
    		</Grid.ColumnDefinitions>
    		<Grid.RowDefinitions>
    			<RowDefinition Height="*" />
    			<RowDefinition Height="*" />
    		</Grid.RowDefinitions>
    		<Button>Button 1</Button>
    		<Button Grid.Column="1">Button 2</Button>
    		<Button Grid.Row="1" Grid.ColumnSpan="2">Button 3</Button>
    	</Grid>
    </Window>
    
    A Grid with column spanning applied to one of the controls

    We just define two columns and two rows, all of them taking up their equal share of the place. The first two buttons just use the columns normally, but with the third button, we make it take up two columns of space on the second row, using the ColumnSpan attribute.

    This is all so simple that we could have just used a combination of panels to achieve the same effect, but for just slightly more advanced cases, this is really useful. Let's try something which better shows how powerful this is:

    <Window x:Class="WpfTutorialSamples.Panels.GridColRowSpanAdvanced"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="GridColRowSpanAdvanced" Height="300" Width="300">
        <Grid>
    		<Grid.ColumnDefinitions>
    			<ColumnDefinition Width="*" />
    			<ColumnDefinition Width="*" />
    			<ColumnDefinition Width="*" />
    		</Grid.ColumnDefinitions>
    		<Grid.RowDefinitions>
    			<RowDefinition Height="*" />
    			<RowDefinition Height="*" />
    			<RowDefinition Height="*" />
    		</Grid.RowDefinitions>
    		<Button Grid.ColumnSpan="2">Button 1</Button>
    		<Button Grid.Column="3">Button 2</Button>
    		<Button Grid.Row="1">Button 3</Button>
    		<Button Grid.Column="1" Grid.Row="1" Grid.RowSpan="2" Grid.ColumnSpan="2">Button 4</Button>
    		<Button Grid.Column="0" Grid.Row="2">Button 5</Button>
    	</Grid>
    </Window>
    
    A Grid with both column and row spanning applied to several child controls

    With three columns and three rows we would normally have nine cells, but in 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.

    So as you can see, spanning multiple columns and/or rows in a Grid is very easy. In a later article, we will use the spanning, along with all the other Grid techniques in a more practical example.



    GridSplitter

    As you saw in the previous articles, the Grid panel makes it very easy to divide up the available space into individual cells. Using column and row definitions, you can easily decide how much space each row or column 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, with the proper amount of space for it, e.g. 5 pixels. It will then allow the user to drag it from side to side or up and down, while changing the size of the column or row on each of the sides of it. Here's an example:

    <Window x:Class="WpfTutorialSamples.Panels.GridSplitterSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="GridSplitterSample" Height="300" Width="300">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="5" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <TextBlock FontSize="55" HorizontalAlignment="Center" VerticalAlignment="Center" TextWrapping="Wrap">Left side</TextBlock>
            <GridSplitter Grid.Column="1" Width="5" HorizontalAlignment="Stretch" />
            <TextBlock Grid.Column="2" FontSize="55" HorizontalAlignment="Center" VerticalAlignment="Center" TextWrapping="Wrap">Right side</TextBlock>
        </Grid>
    </Window>
    

    A Grid panel with a GridSplitter control

    A Grid panel with a GridSplitter control in action

    As you can see, I've simply created a Grid with two equally wide columns, 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 soon as the mouse is over it, the cursor is changed to reflect that it can be resized.

    Horizontal GridSplitter

    The GridSplitter is very easy to use and of course it supports horizontal splits as well. In fact, you hardly have to change anything to make it work horizontally instead of vertically, as the next example will show:

    <Window x:Class="WpfTutorialSamples.Panels.GridSplitterHorizontalSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="GridSplitterHorizontalSample" Height="300" Width="300">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="*" />
                <RowDefinition Height="5" />
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>
            <TextBlock FontSize="55" HorizontalAlignment="Center" VerticalAlignment="Center" TextWrapping="Wrap">Top</TextBlock>
            <GridSplitter Grid.Row="1" Height="5" HorizontalAlignment="Stretch" />
            <TextBlock Grid.Row="2" FontSize="55" HorizontalAlignment="Center" VerticalAlignment="Center" TextWrapping="Wrap">Bottom</TextBlock>
        </Grid>
    </Window>
    

    A horizontal Grid panel with a GridSplitter control in action

    As you can see, I simply changed the columns into rows and on the GridSplitter, I defined a Height instead of a Width. The GridSplitter figures out the rest on its own, but in case it doesn't, you can use the ResizeDirection property on it to force it into either Rows or Columns mode.



    Using Grid: A contact form

    In the last couple of chapters we went through a lot of theoretic information, each with some very theoretic examples. In this chapter we will combine what we have learned about the Grid so far, into an example that can be 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 almost any type of dialog that you need to create.

    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:

    <Window x:Class="WpfTutorialSamples.Panels.GridContactForm"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="GridContactForm" Height="300" Width="300">
        <Grid>
    		<Grid.RowDefinitions>
    			<RowDefinition Height="Auto" />
    			<RowDefinition Height="Auto" />
    			<RowDefinition Height="*" />
    		</Grid.RowDefinitions>		
    		<TextBox>Name</TextBox>
    		<TextBox Grid.Row="1">E-mail</TextBox>
    		<TextBox Grid.Row="2" AcceptsReturn="True">Comment</TextBox>		
    	</Grid>
    </Window>
    
    A simple contact form using the Grid

    As you can see, the last TextBox simply takes up the remaining space, while the first two only takes up the space they require. Try resizing the window and you will see the comment TextBox resize with it.

    In this very simple example, there are no labels to designate what each of the fields are for. Instead, the explanatory text is inside the TextBox, but this is not generally how a Windows dialog looks. Let's try improving the look and usability a bit:

    <Window x:Class="WpfTutorialSamples.Panels.GridContactFormTake2"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="GridContactFormTake2" Height="300" Width="300">
    	<Grid Margin="10">
    		<Grid.ColumnDefinitions>
    			<ColumnDefinition Width="Auto" />
    			<ColumnDefinition Width="*" />
    		</Grid.ColumnDefinitions>
    		<Grid.RowDefinitions>
    			<RowDefinition Height="Auto" />
    			<RowDefinition Height="Auto" />
    			<RowDefinition Height="*" />
    		</Grid.RowDefinitions>
    		<Label>Name: </Label>
    		<TextBox Grid.Column="1" Margin="0,0,0,10" />
    		<Label Grid.Row="1">E-mail: </Label>
    		<TextBox Grid.Row="1" Grid.Column="1" Margin="0,0,0,10" />
    		<Label Grid.Row="2">Comment: </Label>
    		<TextBox Grid.Row="2" Grid.Column="1" AcceptsReturn="True" />
    	</Grid>
    </Window>
    
    A simple contact form using the Grid - take two

    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:

    <TextBox Grid.ColumnSpan="2" Grid.Row="2" AcceptsReturn="True" />
    
    A simple contact form using the Grid - take three

    So as you can see, the Grid is a very powerful panel. Hopefully you can use all of these techniques when designing your own dialogs.

    advertise here!!!
  • Data Binding ↓

    Introduction to WPF data binding

    advertise here!!!

    Wikipedia describes the concept of data binding very well:

    Data binding is general technique that binds two data/information sources together and maintains synchronization of data.

    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 everything you do. If you come from the world of WinForms, then the huge focus on data binding might scare you a bit, but once you get used to it, you 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 UI layer. Sure, you can set properties on a control manually or you can populate a ListBox by adding items to it from a loop, but the cleanest and purest WPF way is to add a binding between the source and the destination UI element.

    Summary

    In the next chapter, we'll look into a simple example where data binding is used and after that, we'll talk some more about all the possibilities. The concept of data binding is included pretty early in this tutorial, because it's such an integral part of using WPF, which you will see once you explore the rest of the chapters, where it's used almost all of the time.

    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 glimpse of how data binding works, and then save the rest of the data binding articles for later, when you're ready to get some more theory.



    Hello, bound world!

    Just like we started this tutorial with the classic "Hello, world!" example, we'll show you how easy it is to use data binding in WPF with a "Hello, bound world!" example. Let's jump straight into it and then I'll explain it afterwards:

    <Window x:Class="WpfTutorialSamples.DataBinding.HelloBoundWorldSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="HelloBoundWorldSample" Height="110" Width="280">
        <StackPanel Margin="10">
    		<TextBox Name="txtValue" />
    		<WrapPanel Margin="0,10">
    			<TextBlock Text="Value: " FontWeight="Bold" />
    			<TextBlock Text="{Binding Path=Text, ElementName=txtValue}" />
    		</WrapPanel>
    	</StackPanel>
    </Window>
    

    A simple data binding between controls

    This simple example shows how we bind the value of the TextBlock to match the Text property of the TextBox. As you can see from the screenshot, the TextBlock is automatically updated when you enter text into the TextBox. In a non-bound world, this would require us to listen to an event on the TextBox and then update the TextBlock each time the text changes, but with data binding, this connection can be established just by using markup.

    The syntax of a Binding

    All the magic happens between the curly braces, which in XAML encapsulates a Markup Extension. For data binding, we use the Binding extension, which allows us to describe the binding relationship for the Text property. In its most simple form, a binding can look like this:

    {Binding}

    This simply returns the current data context (more about that later). This can definitely be useful, but in the most common situations, you would want to bind a property to another property on the data context. A binding like that would look like this:

    {Binding Path=NameOfProperty}

    The Path notes the property that you want to bind to, however, since Path is the default property of a binding, you may leave it out if you want to, like this:

    {Binding NameOfProperty}

    You will see many different examples, some of them where Path is explicitly defined and some where it's left out. In the end it's really up to you though.

    A binding has many other properties though, one of them being the ElementName which we use in our example. This allows us to connect directly to another UI element as the source. Each property that we set in the binding is separated by a comma:

    {Binding Path=Text, ElementName=txtValue}

    Summary

    This was just a glimpse of all the binding possibilities of WPF. In the next chapters, we'll discover more of them, to show you just how powerful data binding is.



    Using the DataContext

    The DataContext property is the default source of your bindings, unless you specifically declare another source, like we did in the previous chapter with the ElementName property. It's defined on the FrameworkElement class, 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 the start), but since a DataContext is inherited down through the control hierarchy, you can set a DataContext for the Window itself and then use it throughout all of the child controls. Let's try illustrating that with a simple example:

    <Window x:Class="WpfTutorialSamples.DataBinding.DataContextSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="DataContextSample" Height="130" Width="280">
    	<StackPanel Margin="15">
    		<WrapPanel>
    			<TextBlock Text="Window title:  " />
    			<TextBox Text="{Binding Title, UpdateSourceTrigger=PropertyChanged}" Width="150" />
    		</WrapPanel>
    		<WrapPanel Margin="0,10,0,0">
    			<TextBlock Text="Window dimensions: " />
    			<TextBox Text="{Binding Width}" Width="50" />
    			<TextBlock Text=" x " />
    			<TextBox Text="{Binding Height}" Width="50" />
    		</WrapPanel>
    	</StackPanel>
    </Window>
    
    using System;
    using System.Windows;
    
    namespace WpfTutorialSamples.DataBinding
    {
    	public partial class DataContextSample : Window
    	{
    		public DataContextSample()
    		{
    			InitializeComponent();
    			this.DataContext = this;
    		}
    	}
    }
    
    

    Several data bindings using the DataContext

    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 be the data context.

    In the XAML, we use this fact to bind to several of the Window properties, including Title, Width and Height. Since the window has a DataContext, 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.

    Try running the example and resize the window - you will see that the dimension changes are immediately reflected in the textboxes. You can also try writing a different title in the first textbox, but you might be surprised to see that this change is not reflected immediately. Instead, you have to move the focus to another control before the change is applied. Why? Well, that's the subject for the next chapter.

    Summary

    Using the DataContext property is like setting the basis of all bindings down through the hierarchy of controls. This saves you the hassle of manually defining a source for each binding, and once you really start using data bindings, you will definitely appreciate the time and typing saved.

    However, this doesn't mean that you have to use the same DataContext for all controls within a Window. Since each control has its own DataContext property, you can easily break the chain of inheritance and override the DataContext with a new value. This allows you to do stuff like having a global DataContext on the window and then a more local and specific DataContext on e.g. a panel holding a separate form or something along those lines.



    The UpdateSourceTrigger property

    In the previous article we saw how changes in a TextBox was not immediately sent back to the source. Instead, the source was updated only after focus was lost on the TextBox. This behavior is controlled by a property 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), while the Text property is updated when focus on the destination element is lost (LostFocus).

    Default is, obviously, the default value of the UpdateSourceTrigger. The other options are PropertyChanged, LostFocus and Explicit. The first two has already been described, while the last one simply means that the update has to be pushed manually through to occur, using a call to UpdateSource on the Binding.

    To see how all of these options work, I have updated the example from the previous chapter to show you all of them:

    <Window x:Class="WpfTutorialSamples.DataBinding.DataContextSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="DataContextSample" Height="130" Width="310">
    	<StackPanel Margin="15">
    		<WrapPanel>
    			<TextBlock Text="Window title:  " />
    			<TextBox Name="txtWindowTitle" Text="{Binding Title, UpdateSourceTrigger=Explicit}" Width="150" />
    			<Button Name="btnUpdateSource" Click="btnUpdateSource_Click" Margin="5,0" Padding="5,0">*</Button>
    		</WrapPanel>
    		<WrapPanel Margin="0,10,0,0">
    			<TextBlock Text="Window dimensions: " />
    			<TextBox Text="{Binding Width, UpdateSourceTrigger=LostFocus}" Width="50" />
    			<TextBlock Text=" x " />
    			<TextBox Text="{Binding Height, UpdateSourceTrigger=PropertyChanged}" Width="50" />
    		</WrapPanel>
    	</StackPanel>
    </Window>
    
    using System;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    
    namespace WpfTutorialSamples.DataBinding
    {
    	public partial class DataContextSample : Window
    	{
    		public DataContextSample()
    		{
    			InitializeComponent();
    			this.DataContext = this;
    		}
    
    		private void btnUpdateSource_Click(object sender, RoutedEventArgs e)
    		{
    			BindingExpression binding = txtWindowTitle.GetBindingExpression(TextBox.TextProperty);
    			binding.UpdateSource();
    		}
    	}
    }
    
    

    Several data bindings, each using different UpdateSourceTrigger values

    As you can see, each of the three textboxes now uses a different UpdateSourceTrigger.

    The first one is set to Explicit, which basically means that the source won't be updated unless you manually do it. For that reason, I have added a button next to the TextBox, which will update the source value on demand. In the Code-behind, you will find the Click handler, where we use a couple of lines of code to get the binding from the destination control and then call the UpdateSource() method on it.

    The second TextBox uses the LostFocus value, which is actually the default for a Text binding. It means that the source value will be updated each time the destination control loses focus.

    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.

    Try running the example on your own machine and see how the three textboxes act completely different: The first value doesn't update before you click the button, the second value isn't updated until you leave the TextBox, while the third value updates automatically on each keystroke, text change etc.

    Summary

    The UpdateSourceTrigger property of a binding controls how and when a changed value is sent back to the source. However, since WPF is pretty good at controlling this for you, the default value should suffice for most cases, where you will get the best mix of a constantly updated UI and good performance.

    For those situations where you need more control of the process, this 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 control, you can use the Explicit value and then do the updates manually, but this does take a bit of the fun out of working with data bindings.



    Responding to changes

    So far in this tutorial, we have mostly created bindings between UI elements and existing classes, but in real life applications, you will obviously be binding to your own data objects. This is just as easy, but once you start doing it, you 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.

    Responding to data source changes

    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 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 accomplish, but WPF comes with two very easy solutions that you can use: The ObservableCollection and the INotifyPropertyChanged interface.

    The following example will show you why we need these two things:

    <Window x:Class="WpfTutorialSamples.DataBinding.ChangeNotificationSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="ChangeNotificationSample" Height="150" Width="300">
    	<DockPanel Margin="10">
    		<StackPanel DockPanel.Dock="Right" Margin="10,0,0,0">
    			<Button Name="btnAddUser" Click="btnAddUser_Click">Add user</Button>
    			<Button Name="btnChangeUser" Click="btnChangeUser_Click" Margin="0,5">Change user</Button>
    			<Button Name="btnDeleteUser" Click="btnDeleteUser_Click">Delete user</Button>
    		</StackPanel>
    		<ListBox Name="lbUsers" DisplayMemberPath="Name"></ListBox>
    	</DockPanel>
    </Window>
    
    using System;
    using System.Collections.Generic;
    using System.Windows;
    
    namespace WpfTutorialSamples.DataBinding
    {
    	public partial class ChangeNotificationSample : Window
    	{
    		private List<User> users = new List<User>();
    
    		public ChangeNotificationSample()
    		{
    			InitializeComponent();
    
    			users.Add(new User() { Name = "John Doe" });
    			users.Add(new User() { Name = "Jane Doe" });
    
    			lbUsers.ItemsSource = users;
    		}
    
    		private void btnAddUser_Click(object sender, RoutedEventArgs e)
    		{
    			users.Add(new User() { Name = "New user" });
    		}
    
    		private void btnChangeUser_Click(object sender, RoutedEventArgs e)
    		{
    			if(lbUsers.SelectedItem != null)
    				(lbUsers.SelectedItem as User).Name = "Random Name";
    		}
    
    		private void btnDeleteUser_Click(object sender, RoutedEventArgs e)
    		{
    			if(lbUsers.SelectedItem != null)
    				users.Remove(lbUsers.SelectedItem as User);
    		}
    	}
    
    	public class User
    	{
    		public string Name { get; set; }
    	}
    }
    

    Not receiving change notifications

    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 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 quick list of a couple of users that we create in the window constructor. The problem is that none of the buttons seems to work. Let's fix that, in two easy steps.

    Reflecting changes in the list data source

    The first step is to get the UI to respond to changes in the list source (ItemsSource), like when we add or delete a user. What we need is a list that 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.

    In the final example, which you will find below, we have simply replaced the List<User> with an ObservableCollection<User> - that's all it takes! This will make the Add and Delete button work, but it won't do anything for the "Change name" button, because the change will happen on the bound data object itself and not the source list - the second step will handle that scenario though.

    Reflecting changes in the data objects

    The second step is to let our custom User class implement the INotifyPropertyChanged interface. By doing that, our User objects are capable of alerting the UI layer of changes to its properties. This is a bit more cumbersome than just changing the list type, like we did above, but it's still one of the simplest way to accomplish these automatic updates.

    The final and working example

    With the two changes described above, we now have an example that WILL reflect changes in the data source. It looks like this:

    <Window x:Class="WpfTutorialSamples.DataBinding.ChangeNotificationSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="ChangeNotificationSample" Height="135" Width="300">
    	<DockPanel Margin="10">
    		<StackPanel DockPanel.Dock="Right" Margin="10,0,0,0">
    			<Button Name="btnAddUser" Click="btnAddUser_Click">Add user</Button>
    			<Button Name="btnChangeUser" Click="btnChangeUser_Click" Margin="0,5">Change user</Button>
    			<Button Name="btnDeleteUser" Click="btnDeleteUser_Click">Delete user</Button>
    		</StackPanel>
    		<ListBox Name="lbUsers" DisplayMemberPath="Name"></ListBox>
    	</DockPanel>
    </Window>
    
    using System;
    using System.Collections.Generic;
    using System.Windows;
    using System.ComponentModel;
    using System.Collections.ObjectModel;
    
    namespace WpfTutorialSamples.DataBinding
    {
    	public partial class ChangeNotificationSample : Window
    	{
    		private ObservableCollection<User> users = new ObservableCollection<User>();
    
    		public ChangeNotificationSample()
    		{
    			InitializeComponent();
    
    			users.Add(new User() { Name = "John Doe" });
    			users.Add(new User() { Name = "Jane Doe" });
    
    			lbUsers.ItemsSource = users;
    		}
    
    		private void btnAddUser_Click(object sender, RoutedEventArgs e)
    		{
    			users.Add(new User() { Name = "New user" });
    		}
    
    		private void btnChangeUser_Click(object sender, RoutedEventArgs e)
    		{
    			if(lbUsers.SelectedItem != null)
    				(lbUsers.SelectedItem as User).Name = "Random Name";
    		}
    
    		private void btnDeleteUser_Click(object sender, RoutedEventArgs e)
    		{
    			if(lbUsers.SelectedItem != null)
    				users.Remove(lbUsers.SelectedItem as User);
    		}
    	}
    
    	public class User : INotifyPropertyChanged
    	{
    		private string name;
    		public string Name {
    			get { return this.name; }
    			set
    			{
    				if(this.name != value)
    				{
    					this.name = value;
    					this.NotifyPropertyChanged("Name");
    				}
    			}
    		}
    
    		public event PropertyChangedEventHandler PropertyChanged;
    
    		public void NotifyPropertyChanged(string propName)
    		{
    			if(this.PropertyChanged != null)
    				this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
    		}
    	}
    }
    

    Receiving change notifications

    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.



    Value conversion with IValueConverter

    So far we have used some simple data bindings, where the sending and receiving property was always compatible. However, you will soon run into situations where you want to use a bound value of one type and then present it slightly differently.

    When to use a value converter

    Value converters are very frequently used with data bindings. Here are some basic examples:

    • 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 string like "yes" or "no" instead of a Boolean value
    • You have a file size in bytes but you wish to show it as bytes, kilobytes, megabytes or gigabytes based on how big it is

    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 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 image for an ImageSource, based on the value, like a green sign for true or a red sign for false - the possibilities are pretty much endless!

    For cases like this, you can use a value converter. These small classes, which implement the IValueConverter interface, will act like middlemen and 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.

    Implementing a simple value converter

    As mentioned, a WPF value converter needs to implement the IValueConverter interface, or alternatively, the IMultiValueConverter interface (more about that one later). Both interfaces just requires you to implement two methods: Convert() and ConvertBack(). As the name implies, these methods will be used to convert the value to the destination format and then back again.

    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 WPF, and you likely are since you're reading this tutorial, then you might not know all of the concepts used in the example, but don't worry, they will all be explained after the code listings:

    <Window x:Class="WpfTutorialSamples.DataBinding.ConverterSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    		xmlns:local="clr-namespace:WpfTutorialSamples.DataBinding"
            Title="ConverterSample" Height="140" Width="250">
    	<Window.Resources>
    		<local:YesNoToBooleanConverter x:Key="YesNoToBooleanConverter" />
    	</Window.Resources>
    	<StackPanel Margin="10">
    		<TextBox Name="txtValue" />
    		<WrapPanel Margin="0,10">
    			<TextBlock Text="Current value is: " />
    			<TextBlock Text="{Binding ElementName=txtValue, Path=Text, Converter={StaticResource YesNoToBooleanConverter}}"></TextBlock>
    		</WrapPanel>
    		<CheckBox IsChecked="{Binding ElementName=txtValue, Path=Text, Converter={StaticResource YesNoToBooleanConverter}}" Content="Yes" />
    	</StackPanel>
    </Window>
    
    using System;
    using System.Windows;
    using System.Windows.Data;
    
    namespace WpfTutorialSamples.DataBinding
    {
    	public partial class ConverterSample : Window
    	{
    		public ConverterSample()
    		{
    			InitializeComponent();
    		}
    	}
    
    	public class YesNoToBooleanConverter : IValueConverter
    	{
    		public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    		{
    			switch(value.ToString().ToLower())
    			{
    				case "yes":
    				case "oui":
    					return true;
    				case "no":
    				case "non":
    					return false;
    			}
    			return false;
    		}
    
    		public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    		{
    			if(value is bool)
    			{
    				if((bool)value == true)
    					return "yes";
    				else
    					return "no";
    			}
    			return "no";
    		}
    	}
    }
    
    

    Using an IValueConverter, here with an empty value Using an IValueConverter, here with a value that converts to false Using an IValueConverter, here with a value that converts to true

    Code-behind

    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 YesNoToBooleanConverter. As advertised, it just implements the two required methods, called Convert() and ConvertBack(). The Convert() 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 as well.

    The ConvertBack() method obviously does the opposite: It assumes an input value with a Boolean type and then returns the English word "yes" or "no" in return, with a fallback value of "no".

    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.

    XAML

    In the XAML part of the program, we start off by declaring an instance of our 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 are happening: We bind the value of the TextBox to the TextBlock and the CheckBox control and using the Converter property and our own converter reference, we juggle the values back and forth between a string and a Boolean value, depending on what's needed.

    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



    StringFormat property

    As we saw in the previous chapters, the way to manipulate the output of a binding before is shown is typically through the use of a converter. The cool thing about the converters is that they allow you to convert any data type into 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.

    Using the StringFormat property of a binding, you lose some of the flexibility 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.

    The StringFormat property does exactly what the name implies: It formats the output string, simply by calling the String.Format method. Sometimes an example says more than a thousand words, so before I hit that word count, let's jump straight into an example:

    <Window x:Class="WpfTutorialSamples.DataBinding.StringFormatSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    		xmlns:system="clr-namespace:System;assembly=mscorlib"
            Title="StringFormatSample" Height="150" Width="250"
    		Name="wnd">
    	<StackPanel Margin="10">
    		<TextBlock Text="{Binding ElementName=wnd, Path=ActualWidth, StringFormat=Window width: {0:#,#.0}}" />
    		<TextBlock Text="{Binding ElementName=wnd, Path=ActualHeight, StringFormat=Window height: {0:C}}" />
    		<TextBlock Text="{Binding Source={x:Static system:DateTime.Now}, StringFormat=Date: {0:dddd, MMMM dd}}" />
    		<TextBlock Text="{Binding Source={x:Static system:DateTime.Now}, StringFormat=Time: {0:HH:mm}}" />
    	</StackPanel>
    </Window>
    
    

    Several data bindings using the StringFormat property to control the output

    The first couple of TextBlock's gets their value by binding to the parent Window and getting its width and height. Through the StringFormat property, the values are formatted. For the width, we specify a custom formatting string and for the height, we ask it to use the currency format, just for fun. The value is saved as a double type, so we can use all the same format specifiers as if we had called double.ToString(). You can find a list of them here: http://msdn.microsoft.com/en-us/library/dwhawy9k.aspx

    Also notice how I can include custom text in the StringFormat - this allows you to pre/post-fix the bound value with text as you please. When referencing 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.

    For the last two values, we simply bind to the current date (DateTime.Now) and the output it first as a date, in a specific format, and then as the time (hours and minutes), again using our own, pre-defined format. You can read more about DateTime formatting here: http://msdn.microsoft.com/en-us/library/az4se3k1.aspx

    Formatting without extra text

    Please be aware that if you specify a format string that doesn't include any custom text, which all of the examples above does, then you need to add an extra set of curly braces, when defining it in XAML. The reason is that WPF may otherwise confuse the syntax with the one used for Markup Extensions. Here's an example:

    <Window x:Class="WpfTutorialSamples.DataBinding.StringFormatSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    		xmlns:system="clr-namespace:System;assembly=mscorlib"
            Title="StringFormatSample" Height="150" Width="250"
    		Name="wnd">
    	<WrapPanel Margin="10">
    		<TextBlock Text="Width: " />
    		<TextBlock Text="{Binding ElementName=wnd, Path=ActualWidth, StringFormat={}{0:#,#.0}}" />
    	</WrapPanel>
    </Window>
    

    Using a specific Culture

    If you need to output a bound value in accordance with a specific culture, that's no problem. The Binding will use the language specified for the parent element, or you can specify it directly for the binding, using the ConverterCulture property. Here's an example:

    <Window x:Class="WpfTutorialSamples.DataBinding.StringFormatCultureSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    		xmlns:system="clr-namespace:System;assembly=mscorlib"
            Title="StringFormatCultureSample" Height="120" Width="300">
    	<StackPanel Margin="10">
    		<TextBlock Text="{Binding Source={x:Static system:DateTime.Now}, ConverterCulture='de-DE', StringFormat=German date: {0:D}}" />
    		<TextBlock Text="{Binding Source={x:Static system:DateTime.Now}, ConverterCulture='en-US', StringFormat=American date: {0:D}}" />
    		<TextBlock Text="{Binding Source={x:Static system:DateTime.Now}, ConverterCulture='ja-JP', StringFormat=Japanese date: {0:D}}" />
    	</StackPanel>
    </Window>
    
    

    Several data bindings using the StringFormat property, with a specific ConverterCulture, to control the output

    It's pretty simple: By combining the StringFormat property, which uses the D specifier (Long date pattern) and the ConverterCulture property, we can output the bound values in accordance with a specific culture. Pretty nifty!



    Debugging data bindings

    Since data bindings are evaluated at runtime, and no exceptions are thrown when they fail, a bad binding can sometimes be very hard to track down. These problems can occur in several different situations, but a common issue 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:

    <Window x:Class="WpfTutorialSamples.DataBinding.DataBindingDebuggingSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="DataBindingDebuggingSample" Height="100" Width="200">
        <Grid Margin="10" Name="pnlMain">
    		<TextBlock Text="{Binding NonExistingProperty, ElementName=pnlMain}" />
    	</Grid>
    </Window>
    

    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 by using the [Ctrl+Alt+O] shortcut. There will be loads of output from the debugger, but somewhere you should find a line like this, when running the above example:

    System.Windows.Data Error: 40 : BindingExpression path error: 'NonExistingProperty' property not found on 'object' ''Grid' (Name='pnlMain')'. BindingExpression:Path=NonExistingProperty; DataItem='Grid' (Name='pnlMain'); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')

    This might seem a bit overwhelming, mainly because no linebreaks are used in this long message, but the important part is this:

    'NonExistingProperty' property not found on 'object' ''Grid' (Name='pnlMain')'.

    It tells you that you have tried to use a property called "NonExistingProperty" on an object of the type Grid, with the name pnlMain. That's actually pretty concise and should help you correct the name of the property or bind to the real object, if that's the problem.

    Adjusting the trace level

    The above example was easy to fix, because it was clear to WPF what we were trying to do and why it didn't work. Consider this next example though:

    <Window x:Class="WpfTutorialSamples.DataBinding.DataBindingDebuggingSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="DataBindingDebuggingSample" Height="100" Width="200">
        <Grid Margin="10">
    		<TextBlock Text="{Binding Title}" />
    	</Grid>
    </Window>
    

    I'm trying to bind to the property "Title", but on which object? As stated in the article on data contexts, WPF will use the DataContext property on the TextBlock here, which may be inherited down the control hierarchy, but in this example, I forgot to assign a data context. This basically means that I'm 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 the Output window, you won't see any binding errors.

    However, for the cases where this is not the behavior that you're expecting, there is a way to force WPF into telling you about all the binding problems it runs into. It can be done by setting the TraceLevel on the PresentationTraceSources object, which can be found in the System.Diagnostics namespace:

    <Window x:Class="WpfTutorialSamples.DataBinding.DataBindingDebuggingSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
            Title="DataBindingDebuggingSample" Height="100" Width="200">
        <Grid Margin="10">
    		<TextBlock Text="{Binding Title, diag:PresentationTraceSources.TraceLevel=High}" />
    	</Grid>
    </Window>
    

    Notice that I have added a reference to the System.Diagnostics namespace in the top, and then used the property on the binding. WPF will now give you loads of information about this specific binding in the Output window:

    System.Windows.Data Warning: 55 : Created BindingExpression (hash=2902278) for Binding (hash=52760599)
    System.Windows.Data Warning: 57 :   Path: 'Title'
    System.Windows.Data Warning: 59 : BindingExpression (hash=2902278): Default mode resolved to OneWay
    System.Windows.Data Warning: 60 : BindingExpression (hash=2902278): Default update trigger resolved to PropertyChanged
    System.Windows.Data Warning: 61 : BindingExpression (hash=2902278): Attach to System.Windows.Controls.TextBlock.Text (hash=18876224)
    System.Windows.Data Warning: 66 : BindingExpression (hash=2902278): Resolving source
    System.Windows.Data Warning: 69 : BindingExpression (hash=2902278): Found data context element: TextBlock (hash=18876224) (OK)
    System.Windows.Data Warning: 70 : BindingExpression (hash=2902278): DataContext is null
    System.Windows.Data Warning: 64 : BindingExpression (hash=2902278): Resolve source deferred
    System.Windows.Data Warning: 66 : BindingExpression (hash=2902278): Resolving source
    System.Windows.Data Warning: 69 : BindingExpression (hash=2902278): Found data context element: TextBlock (hash=18876224) (OK)
    System.Windows.Data Warning: 70 : BindingExpression (hash=2902278): DataContext is null
    System.Windows.Data Warning: 66 : BindingExpression (hash=2902278): Resolving source
    System.Windows.Data Warning: 69 : BindingExpression (hash=2902278): Found data context element: TextBlock (hash=18876224) (OK)
    System.Windows.Data Warning: 70 : BindingExpression (hash=2902278): DataContext is null
    System.Windows.Data Warning: 66 : BindingExpression (hash=2902278): Resolving source
    System.Windows.Data Warning: 69 : BindingExpression (hash=2902278): Found data context element: TextBlock (hash=18876224) (OK)
    System.Windows.Data Warning: 70 : BindingExpression (hash=2902278): DataContext is null
    System.Windows.Data Warning: 66 : BindingExpression (hash=2902278): Resolving source  (last chance)
    System.Windows.Data Warning: 69 : BindingExpression (hash=2902278): Found data context element: TextBlock (hash=18876224) (OK)
    System.Windows.Data Warning: 77 : BindingExpression (hash=2902278): Activate with root item <null>
    System.Windows.Data Warning: 105 : BindingExpression (hash=2902278):   Item at level 0 is null - no accessor
    System.Windows.Data Warning: 79 : BindingExpression (hash=2902278): TransferValue - got raw value {DependencyProperty.UnsetValue}
    System.Windows.Data Warning: 87 : BindingExpression (hash=2902278): TransferValue - using fallback/default value ''
    System.Windows.Data Warning: 88 : BindingExpression (hash=2902278): TransferValue - using final value ''
    

    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 end, it uses the default {DependencyProperty.UnsetValue} which translates into an empty string.

    Using the real debugger

    The above trick can be great for diagnosing a bad binding, but for some 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.DataBindingDebuggingSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            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();
    		}
    	}
    
    	public class DebugDummyConverter : IValueConverter
    	{
    		public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    		{
    			Debugger.Break();
    			return value;
    		}
    
    		public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    		{
    			Debugger.Break();
    			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.

    advertise here!!!
  • Defense ↓

    Introduction to WPF Commands

    advertise here!!!

    In a previous chapter of this tutorial, we talked about how to handle events, e.g. when the user clicks on a button or a menu item. In a modern user interface, it's typical for a function to be reachable from several places 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 toolbar, in a context menu (e.g. when right clicking in the main application area) and from a keyboard shortcut like Ctrl+N and Ctrl+O.

    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 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 handle the keyboard shortcut. Not an ideal situation.

    Commands

    With WPF, Microsoft is trying to remedy that with a concept called 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 and so on. WPF will also listen for keyboard shortcuts and pass them along to the proper command, if any, making it the ideal way to offer keyboard shortcuts in an application.

    Commands also solve another hassle when dealing with multiple entrances 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 clipboard command like Cut, but only when text was selected, you would have to manually enable and disable the main menu item, the toolbar button and the context menu item each time text selection changed.

    With WPF commands, this is centralized. With one method you decide whether or not a given command can be executed, and then WPF toggles all the subscribing interface elements on or off automatically. This makes it so much easier to create a responsive and dynamic application!

    Command bindings

    Commands don't actually do anything by them self. At the root, they consist of the ICommand interface, which only defines an event and two methods: Execute() and CanExecute(). The first one is for performing the actual action, while the second one is for determining whether the action is currently available. To perform the actual action of the command, you need a link between the command and your code and this is where the CommandBinding comes into play.

    A CommandBinding is usually defined on a Window or a UserControl, and holds a references to the Command that it handles, as well as the actual event handlers for dealing with the Execute() and CanExecute() events of the Command.

    Pre-defined commands

    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 defined over 100 commonly used commands that you can use. They have been divided into 5 categories, called ApplicationCommands, NavigationCommands, MediaCommands, EditingCommands and ComponentCommands. Especially ApplicationCommands contains commands for a lot of very frequently used actions like New, Open, Save and Cut, Copy and Paste.

    Summary

    Commands help you to respond to a common action from several different sources, using a single event handler. It also makes it a lot easier to enable 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.



    Using WPF commands

    In the previous article, we discussed a lot of theory about what commands are and how they work. In this chapter, we'll look into how you actually use commands, by assigning them to user interface elements and creating command bindings that links it all together.

    We'll start off with a very simple example:

    <Window x:Class="WpfTutorialSamples.Commands.UsingCommandsSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="UsingCommandsSample" Height="100" Width="200">
        <Window.CommandBindings>
            <CommandBinding Command="ApplicationCommands.New" Executed="NewCommand_Executed" CanExecute="NewCommand_CanExecute" />
        </Window.CommandBindings>
    
        <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
            <Button Command="ApplicationCommands.New">New</Button>
        </StackPanel>
    </Window>
    
    using System;
    using System.Collections.Generic;
    using System.Windows;
    using System.Windows.Input;
    
    namespace WpfTutorialSamples.Commands
    {
    	public partial class UsingCommandsSample : Window
    	{
    		public UsingCommandsSample()
    		{
    			InitializeComponent();
    		}
    
    		private void NewCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
    		{
    			e.CanExecute = true;
    		}
    
    		private void NewCommand_Executed(object sender, ExecutedRoutedEventArgs e)
    		{
    			MessageBox.Show("The New command was invoked");
    		}
    	}
    }
    

    An interface using a WPF command

    We define a command binding on the Window, by adding it to its CommandBindings collection. We specify that Command that we wish to use (the New command from the ApplicationCommands), as well as two event handlers. The visual interface consists of a single button, which we attach the command to using the Command property.

    In Code-behind, we handle the two events. The CanExecute handler, which 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 CanExecute property of the event arguments to true.

    The Executed handler simply shows a message box when the command is invoked. If you run the sample and press the button, you will see this message. A thing to notice is that this command has a default keyboard shortcut defined, which you get as an added bonus. Instead of clicking the button, you can try to press Ctrl+N on your keyboard - the result is the same.

    Using the CanExecute method

    In the first example, we implemented a CanExecute event that simply returned true, so that the button would be available all the time. However, this is of course not true for all buttons - in many cases, you want the button to be enabled or disabled depending on some sort of state in your application.

    A very common example of this is the toggling of buttons for using the Windows Clipboard, where you want the Cut and Copy buttons to be enabled only when text is selected, and the Paste button to only be enabled when text is present in the clipboard. This is exactly what we'll accomplish in this example:

    <Window x:Class="WpfTutorialSamples.Commands.CommandCanExecuteSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="CommandCanExecuteSample" Height="200" Width="250">
        <Window.CommandBindings>
            <CommandBinding Command="ApplicationCommands.Cut" CanExecute="CutCommand_CanExecute" Executed="CutCommand_Executed" />
            <CommandBinding Command="ApplicationCommands.Paste" CanExecute="PasteCommand_CanExecute" Executed="PasteCommand_Executed" />
        </Window.CommandBindings>
        <DockPanel>
            <WrapPanel DockPanel.Dock="Top" Margin="3">
                <Button Command="ApplicationCommands.Cut" Width="60">_Cut</Button>
                <Button Command="ApplicationCommands.Paste" Width="60" Margin="3,0">_Paste</Button>
            </WrapPanel>
            <TextBox AcceptsReturn="True" Name="txtEditor" />
        </DockPanel>
    </Window>
    
    using System;
    using System.Collections.Generic;
    using System.Windows;
    using System.Windows.Input;
    
    namespace WpfTutorialSamples.Commands
    {
    	public partial class CommandCanExecuteSample : Window
    	{
    		public CommandCanExecuteSample()
    		{
    			InitializeComponent();
    		}
    
    		private void CutCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
    		{
    			e.CanExecute = (txtEditor != null) && (txtEditor.SelectionLength > 0);
    		}
    
    		private void CutCommand_Executed(object sender, ExecutedRoutedEventArgs e)
    		{
    			txtEditor.Cut();
    		}
    
    		private void PasteCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
    		{
    			e.CanExecute = Clipboard.ContainsText();
    		}
    
    		private void PasteCommand_Executed(object sender, ExecutedRoutedEventArgs e)
    		{
    			txtEditor.Paste();
    		}
    	}
    }
    

    WPF command using the CanExecute method

    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.CommandsWithCommandTargetSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            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>
    

    WPF command with command targets

    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.



    Implementing a custom WPF Command

    In the previous chapter, we looked at various ways of using commands already defined in WPF, but of course you can implement your own 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 static class that will contain them. Each command is then added to this class as static fields, allowing you to use them in your application. Since WPF, for some strange reason, doesn't implement an Exit/Quit command, I decided to implement one for our custom commands example. It looks like this:

    <Window x:Class="WpfTutorialSamples.Commands.CustomCommandSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:self="clr-namespace:WpfTutorialSamples.Commands"
            Title="CustomCommandSample" Height="150" Width="200">
        <Window.CommandBindings>
            <CommandBinding Command="self:CustomCommands.Exit" CanExecute="ExitCommand_CanExecute" Executed="ExitCommand_Executed" />
        </Window.CommandBindings>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>
            <Menu>
                <MenuItem Header="File">
                    <MenuItem Command="self:CustomCommands.Exit" />
                </MenuItem>
            </Menu>
            <StackPanel Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center">
                <Button Command="self:CustomCommands.Exit">Exit</Button>
            </StackPanel>
        </Grid>
    </Window>
    
    using System;
    using System.Collections.Generic;
    using System.Windows;
    using System.Windows.Input;
    
    namespace WpfTutorialSamples.Commands
    {
    	public partial class CustomCommandSample : Window
    	{
    		public CustomCommandSample()
    		{
    			InitializeComponent();
    		}
    
    		private void ExitCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
    		{
    			e.CanExecute = true;
    		}
    
    		private void ExitCommand_Executed(object sender, ExecutedRoutedEventArgs e)
    		{
    			Application.Current.Shutdown();
    		}
    	}
    
    	public static class CustomCommands
    	{
    		public static readonly RoutedUICommand Exit = new RoutedUICommand
    			(
    				"Exit",
    				"Exit",
    				typeof(CustomCommands),
    				new InputGestureCollection()
    				{
    					new KeyGesture(Key.F4, ModifierKeys.Alt)
    				}
    			);
    
    		//Define more commands here, just like the one above
    	}
    }
    

    An interface using a custom WPF command

    In the markup, I've defined a very simple interface with a menu and a button, both of them using our new, custom Exit command. This command is defined in Code-behind, in our own CustomCommands class, and then referenced 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.

    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" namespace defined in the top) instead of a built-in command.

    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 terminate our application. All very simple.

    As already explained, we implement our Exit command as a field on a static 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 parameters are the text/label of the command, the name of the command, the owner type and then an InputGestureCollection, allowing me to define a default shortcut for the command (Alt+F4).

    Summary

    Implementing custom WPF commands is almost as easy as consuming the built-in commands, and it allows you to use commands for every purpose in your application. This makes it very easy to re-use actions in several places, as shown in the example of this chapter.

    advertise here!!!
  • Dialogs ↓

    MessageBox

    advertise here!!!

    WPF offers several dialogs for your application to utilize, but the simplest one is definitely the MessageBox. Its sole purpose is to show a message to the user, and then offer one or several ways for the user to respond to the message.

    The MessageBox is used by calling the static Show() method, which can take a range of different parameters, to be able to look and behave the way you want it to. We'll be going through all the various forms in this article, with each variation represented by the MessageBox.Show() line and a screenshot of the result. In the end of the article, you can find a complete example which lets you test all the variations.

    In its simplest form, the MessageBox just takes a single parameter, which is the message to be displayed:

    MessageBox.Show("Hello, world!");
    

    A simple MessageBox

    MessageBox with a title

    The above example might be a bit too bare minimum - a title on the window displaying the message would probably help. Fortunately, the second and optional parameter allows us to specify the title:

    MessageBox.Show("Hello, world!", "My App");
    

    A MessageBox with a title

    MessageBox with extra buttons

    By default, the MessageBox only has the one Ok button, but this can be changed, in case you want to ask your user a question and not just show a piece of information. Also notice how I use multiple lines in this message, by using a line break character (\n):

    MessageBox.Show("This MessageBox has extra options.\n\nHello, world?", "My App", MessageBoxButton.YesNoCancel);
    

    You control which buttons are displayed by using a value from the MessageBoxButton enumeration - in this case, a Yes, No and Cancel button is included. The following values, which should be self-explanatory, can be used:

    • OK
    • OKCancel
    • YesNoCancel
    • YesNo

    Now with multiple choices, you need a way to be able to see what the user chose, and fortunately, the MessageBox.Show() method always returns a value from the MessageBoxResult enumeration that you can use. Here's an example:

    MessageBoxResult result = MessageBox.Show("Would you like to greet the world with a \"Hello, world\"?", "My App", MessageBoxButton.YesNoCancel);
    switch(result)
    {
    	case MessageBoxResult.Yes:
    		MessageBox.Show("Hello to you too!", "My App");
    		break;
    	case MessageBoxResult.No:
    		MessageBox.Show("Oh well, too bad!", "My App");
    		break;
    	case MessageBoxResult.Cancel:
    		MessageBox.Show("Nevermind then...", "My App");
    		break;
    }
    

    A MessageBox with extra buttons

    A MessageBox showing the response

    By checking the result value of the MessageBox.Show() method, you can now react to the user choice, as seen in the code example as well as on the screenshots.

    MessageBox with an icon

    The MessageBox has the ability to show a pre-defined icon to the left of the text message, by using a fourth parameter:

    MessageBox.Show("Hello, world!", "My App", MessageBoxButton.OK, MessageBoxImage.Information);
    

    A MessageBox with an icon

    Using the MessageBoxImage enumeration, you can choose between a range of icons for different situations. Here's the complete list:

    • Asterisk
    • Error
    • Exclamation
    • Hand
    • Information
    • None
    • Question
    • Stop
    • Warning

    The names should say a lot about how they look, but feel free to experiment with the various values or have a look at this MSDN article, where each value is explained and even illustrated: http://msdn.microsoft.com/en-us/library/system.windows.messageboximage.aspx

    MessageBox with a default option

    The MessageBox will select a button as the default choice, which is then the button invoked in case the user just presses Enter once the dialog is shown. For instance, if you display a MessageBox with a "Yes" and a "No" button, "Yes" will be the default answer. You can change this behavior using a fifth parameter to the MessageBox.Show() method though:

    MessageBox.Show("Hello, world?", "My App", MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No);
    

    A MessageBox with a default option

    Notice on the screenshot how the "No" button is slightly elevated, to visually indicate that it is selected and will be invoked if the Enter or Space button is pressed.

    The complete example

    As promised, here's the complete example used in this article:

    <Window x:Class="WpfTutorialSamples.Dialogs.MessageBoxSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MessageBoxSample" Height="250" Width="300">
        <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
            <StackPanel.Resources>
                <Style TargetType="Button">
                    <Setter Property="Margin" Value="0,0,0,10" />
                </Style>
            </StackPanel.Resources>
            <Button Name="btnSimpleMessageBox" Click="btnSimpleMessageBox_Click">Simple MessageBox</Button>
            <Button Name="btnMessageBoxWithTitle" Click="btnMessageBoxWithTitle_Click">MessageBox with title</Button>
            <Button Name="btnMessageBoxWithButtons" Click="btnMessageBoxWithButtons_Click">MessageBox with buttons</Button>
            <Button Name="btnMessageBoxWithResponse" Click="btnMessageBoxWithResponse_Click">MessageBox with response</Button>
            <Button Name="btnMessageBoxWithIcon" Click="btnMessageBoxWithIcon_Click">MessageBox with icon</Button>
            <Button Name="btnMessageBoxWithDefaultChoice" Click="btnMessageBoxWithDefaultChoice_Click">MessageBox with default choice</Button>
        </StackPanel>
    </Window>
    
    using System;
    using System.Windows;
    
    namespace WpfTutorialSamples.Dialogs
    {
    	public partial class MessageBoxSample : Window
    	{
    		public MessageBoxSample()
    		{
    			InitializeComponent();
    		}
    
    		private void btnSimpleMessageBox_Click(object sender, RoutedEventArgs e)
    		{
    			MessageBox.Show("Hello, world!");
    		}
    
    		private void btnMessageBoxWithTitle_Click(object sender, RoutedEventArgs e)
    		{
    			MessageBox.Show("Hello, world!", "My App");
    		}
    
    		private void btnMessageBoxWithButtons_Click(object sender, RoutedEventArgs e)
    		{
    			MessageBox.Show("This MessageBox has extra options.\n\nHello, world?", "My App", MessageBoxButton.YesNoCancel);
    		}
    
    		private void btnMessageBoxWithResponse_Click(object sender, RoutedEventArgs e)
    		{
    			MessageBoxResult result = MessageBox.Show("Would you like to greet the world with a \"Hello, world\"?", "My App", MessageBoxButton.YesNoCancel);
    			switch(result)
    			{
    				case MessageBoxResult.Yes:
    					MessageBox.Show("Hello to you too!", "My App");
    					break;
    				case MessageBoxResult.No:
    					MessageBox.Show("Oh well, too bad!", "My App");
    					break;
    				case MessageBoxResult.Cancel:
    					MessageBox.Show("Nevermind then...", "My App");
    					break;
    			}
    		}
    
    		private void btnMessageBoxWithIcon_Click(object sender, RoutedEventArgs e)
    		{
    			MessageBox.Show("Hello, world!", "My App", MessageBoxButton.OK, MessageBoxImage.Information);
    		}
    
    		private void btnMessageBoxWithDefaultChoice_Click(object sender, RoutedEventArgs e)
    		{
    			MessageBox.Show("Hello, world?", "My App", MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No);
    		}
    	}
    }
    


    OpenFileDialog

    Whenever you open or save a file in almost any Windows application, you will see roughly the same dialogs for doing that. The reason is of course that these dialogs are a part of the Windows API and therefore also accessible to developers on the Windows platform.

    For WPF, you will find standard dialogs for both opening and saving files in the Microsoft.Win32 namespace. In this article we'll focus on the OpenFileDialog class, which makes it very easy to display a dialog for opening one or several files.

    Simple OpenFileDialog example

    Let's start off by using the OpenFileDialog without any extra options, to load a file to a TextBox control:

    <Window x:Class="WpfTutorialSamples.Dialogs.OpenFileDialogSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="OpenFileDialogSample" Height="300" Width="300">
        <DockPanel Margin="10">
            <WrapPanel HorizontalAlignment="Center" DockPanel.Dock="Top" Margin="0,0,0,10">
                <Button Name="btnOpenFile" Click="btnOpenFile_Click">Open file</Button>
            </WrapPanel>
            <TextBox Name="txtEditor" />
        </DockPanel>
    </Window>
    
    using System;
    using System.IO;
    using System.Windows;
    using Microsoft.Win32;
    
    namespace WpfTutorialSamples.Dialogs
    {
    	public partial class OpenFileDialogSample : Window
    	{
    		public OpenFileDialogSample()
    		{
    			InitializeComponent();
    		}
    
    		private void btnOpenFile_Click(object sender, RoutedEventArgs e)
    		{
    			OpenFileDialog openFileDialog = new OpenFileDialog();
    			if(openFileDialog.ShowDialog() == true)
    				txtEditor.Text = File.ReadAllText(openFileDialog.FileName);
    		}
    	}
    }
    

    A simple OpenFileDialog example (the application)

    Once you click the Open file button, the OpenFileDialog will be instantiated and shown. Depending on which version of Windows you're using and the theme selected, it will look something like this:

    A simple OpenFileDialog example

    The ShowDialog() will return a nullable boolean value, meaning that it can be either false, true or null. If the user selects a file and presses "Open", the result is True, and in that case, we try to load the file into the TextBox control. We get the complete path of the selected file by using the FileName property of the OpenFileDialog.

    Filter

    Normally when you want your user to open a file in your application, you want to limit it to one or a couple of file types. For instance, Word mostly opens Word file (with the extension .doc or .docx) and Notepad mostly open text files (with the extension .txt).

    You can specify a filter for your OpenFileDialog to indicate to the user which types of file they should be opening in your application, as well as limiting the files shown for a better overview. This is done with the Filter property, which we can add to the above example, right after initializing the dialog, like this:

    openFileDialog.Filter = "Text files (*.txt)|*.txt|All files (*.*)|*.*";
    

    Here's the result:

    A simple OpenFileDialog with a filter selector

    Notice how the dialog now has a combo box for selecting the file types, and that the files shown are limited to ones with the extension(s) specified by the selected file type.

    The format for specifying the filter might look a bit strange at first sight, but it works by specifying a human-readable version of the desired file extension(s) and then one for the computer to easily parse, separated with a pipe (|) character. If you want more than one file type, as we do in the above example, each set of information are also separated with a pipe character.

    So to sum up, the following part means that we want the file type to be named "Text files (*.txt)" (the extension in the parenthesis is a courtesy to the user, so they know which extension(s) are included) and the second part tells the dialog to show files with a .txt extension:

    Text files (*.txt)|*.txt
    

    Each file type can of course have multiple extensions. For instance, image files could be specified as both JPEG and PNG files, like this:

    openFileDialog.Filter = "Image files (*.png;*.jpeg)|*.png;*.jpeg|All files (*.*)|*.*";
    

    Simply separate each extension with a semicolon in the second part (the one for the computer) - in the first part, you can format it the way you want to, but most developers seem to use the same notation for both parts, as seen in the example above.

    Setting the initial directory

    The initial directory used by the OpenFileDialog is decided by Windows, but by using the InitialDirectory property, you can override it. You will usually set this value to a user specified directory, the application directory or perhaps just to the directory last used. You can set it to a path in a string format, like this:

    openFileDialog.InitialDirectory = @"c:\temp\";
    

    If you want to use one of the special folders on Windows, e.g. the Desktop, My Documents or the Program Files directory, you have to take special care, since these may vary from each version of Windows and also be dependent on which user is logged in. The .NET framework can help you though, just use the Environment class and its members for dealing with special folders:

    openFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
    

    In this case, I get the path for the My Documents folder, but have a look at the SpecialFolder enumeration - it contains values for a lot of interesting paths. For a full list, please see this MSDN article.

    Multiple files

    If your application supports multiple open files, or you simply want to use the OpenFileDialog to select more than one file at a time, you need to enable the Multiselect property. In the next example, we've done just that, and as a courtesy to you, dear reader, we've also applied all the techniques mentioned above, including filtering and setting the initial directory:

    <Window x:Class="WpfTutorialSamples.Dialogs.OpenFileDialogMultipleFilesSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="OpenFileDialogMultipleFilesSample" Height="300" Width="300">
        <DockPanel Margin="10">
            <WrapPanel HorizontalAlignment="Center" DockPanel.Dock="Top" Margin="0,0,0,10">
                <Button Name="btnOpenFile" Click="btnOpenFiles_Click">Open files</Button>
            </WrapPanel>
            <ListBox Name="lbFiles" />
        </DockPanel>
    </Window>
    
    using System;
    using System.IO;
    using System.Windows;
    using Microsoft.Win32;
    
    namespace WpfTutorialSamples.Dialogs
    {
    	public partial class OpenFileDialogMultipleFilesSample : Window
    	{
    		public OpenFileDialogMultipleFilesSample()
    		{
    			InitializeComponent();
    		}
    
    		private void btnOpenFiles_Click(object sender, RoutedEventArgs e)
    		{
    			OpenFileDialog openFileDialog = new OpenFileDialog();
    			openFileDialog.Multiselect = true;
    			openFileDialog.Filter = "Text files (*.txt)|*.txt|All files (*.*)|*.*";
    			openFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
    			if(openFileDialog.ShowDialog() == true)
    			{
    				foreach(string filename in openFileDialog.FileNames)
    					lbFiles.Items.Add(Path.GetFileName(filename));
    			}
    		}
    	}
    }
    

    A simple OpenFileDialog with multiple selections

    If you test this code, you will see that you can now select multiple files in the same directory, by holding down either Ctrl orShift and clicking with the mouse. Once accepted, this example simply adds the filenames to the ListBox control, by looping through the FileNames property.

    Summary

    As you can see, using the OpenFileDialog in WPF is very easy and really takes care of a lot of work for you. Please be aware that to reduce the amount of code lines, no exception handling is done in these examples. When working with files and doing IO tasks in general, you should always look out for exceptions, as they can easily occur due to a locked file, non-existing path or related problems.



    SaveFileDialog

    The SaveFileDialog will help you select a location and a filename when you wish to save a file. It works and looks much like the OpenFileDialog which we used in the previous article, with a few subtle differences. Just like the OpenFileDialog, the SaveFileDialog is a wrapper around a common Windows dialog, meaning that your users will see roughly the same dialog whether they initiate it in your application or e.g. in Notepad.

    Simple SaveFileDialog example

    To kick things off, let's begin with a very simple example on using the SaveFileDialog:

    <Window x:Class="WpfTutorialSamples.Dialogs.SaveFileDialogSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="SaveFileDialogSample" Height="300" Width="300">
        <DockPanel Margin="10">
            <WrapPanel HorizontalAlignment="Center" DockPanel.Dock="Top" Margin="0,0,0,10">
                <Button Name="btnSaveFile" Click="btnSaveFile_Click">Save file</Button>
            </WrapPanel>
            <TextBox Name="txtEditor" TextWrapping="Wrap" AcceptsReturn="True" ScrollViewer.VerticalScrollBarVisibility="Auto" />
        </DockPanel>
    </Window>
    
    using System;
    using System.IO;
    using System.Windows;
    using Microsoft.Win32;
    
    namespace WpfTutorialSamples.Dialogs
    {
    	public partial class SaveFileDialogSample : Window
    	{
    		public SaveFileDialogSample()
    		{
    			InitializeComponent();
    		}
    
    		private void btnSaveFile_Click(object sender, RoutedEventArgs e)
    		{
    			SaveFileDialog saveFileDialog = new SaveFileDialog();
    			if(saveFileDialog.ShowDialog() == true)
    				File.WriteAllText(saveFileDialog.FileName, txtEditor.Text);
    		}
    	}
    }
    

    A simple SaveFileDialog example (the application)

    As you can see, it's mostly about instantiating the SaveFileDialog and then calling the ShowDialog() method. If it returns true, we use the FileName property (which will contain the selected path as well as the user entered file name) as the path to write our contents to.

    If you click the save button, you should see a dialog like this, depending on the version of Windows you're using:

    A simple SaveFileDialog example (the dialog)

    Filter

    As you can see from the first example, I manually added a .txt extension to my desired filename, mainly because the "Save as type" combo box is empty. Just like for the OpenFileDialog, this box is controlled through the Filter property, and it's also used in the exact same way.

    saveFileDialog.Filter = "Text file (*.txt)|*.txt|C# file (*.cs)|*.cs";
    

    For more details about the format of the Filter property, please see the previous article on the OpenFileDialog, where it's explained in details.

    With a filter like the above, the resulting SaveFileDialog will look like this instead:

    A SaveFileDialog with a custom Filter

    With that in place, you can write filenames without specifying the extension - it will be taken from the selected file type in the filter combo box instead. This also indicates to the user which file formats your application supports, which is of course important.

    Setting the initial directory

    The initial directory used by the SaveFileDialog is decided by Windows, but by using the InitialDirectory property, you can override it. You will usually set this value to a user specified directory, the application directory or perhaps just to the directory last used. You can set it to a path in a string format, like this:

    saveFileDialog.InitialDirectory = @"c:\temp\";
    

    If you want to use one of the special folders on Windows, e.g. the Desktop, My Documents or the Program Files directory, you have to take special care, since these may vary from each version of Windows and also depend on which user is logged in. The .NET framework can help you though, just use the Environment class and its members for dealing with special folders:

    saveFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
    

    In this case, I get the path for the My Documents folder, but have a look at the SpecialFolder enumeration - it contains values for a lot of interesting paths. For a full list, please see this MSDN article.

    Options

    Besides the options already mentioned in this article, I want to draw your attention to the following properties, which will help you tailor the SaveFileDialog to your needs:

    AddExtension - defaults to true and determines if the SaveFileDialog should automatically append an extension to the filename, if the user omits it. The extension will be based on the selected filter, unless that's not possible, in which case it will fall back to the DefaultExt property (if specified). If you want your application to be able to save files without file extensions, you may have to disable this option.

    OverwritePrompt - defaults to true and determines if the SaveFileDialog should ask for a confirmation if the user enters a file name which will result in an existing file being overwritten. You will normally want to leave this option enabled except in very special situations.

    Title - you may override this property if you want a custom title on your dialog. It defaults to "Save As" or the localized equivalent and the property is also valid for the OpenFileDialog.

    ValidateNames - defaults to true and unless it's disabled, it will ensure that the user enters only valid Windows file names before allowing the user to continue.



    Other Dialogs

    Windows Forms comes with a range of dialogs which we haven't talked about in this tutorial yet, for the simple reason that they don't exist in WPF. The most important one is definitely the FolderBrowserDialog, which lets the user select a folder within the file system, but other dialogs missing in WPF include theColorDialog, theFontDialog, thePrintPreviewDialog and the PageSetupDialog.

    This can be a real problem for WPF developers, since re-implementing these dialogs would be a huge task. Fortunately, WPF and WinForms can be mixed, simply by referencing the System.Windows.Forms assembly, but since WPF uses different base types for both colors and dialogs, this is not always a viable solution. It is however an easy solution if you just need the FolderBrowserDialog, since it only deals with folder paths as simple strings, but some purists would argue that mixing WPF and WinForms is never the way to go.

    A better way to go, if you don't want to reinvent the wheel yourself, might be to use some of the work created by other developers. Here are a couple of links for article which offers a solution to some of the missing dialogs:

    - A FontDialog alternative for WPF

    - A ColorDialog alternative for WPF

    In the end, you should choose the solution which fits the requirements of your application best.



    Creating a custom input dialog

    In the last couple of articles, we've looked at using the built-in dialogs of WPF, but creating your own is almost just as easy. In fact, you really just need to create a Window, place the required controls in it and then show it.

    However, there are a few things that you should remember when creating dialogs, to ensure that your application acts like other Windows applications. In this article, we'll create a very simple dialog to ask the user a question and then return the answer, while discussing the various good practices that you should follow.

    Designing the dialog

    For this particular dialog, I just wanted a Label telling the user which information we need from him/her, a TextBox for entering the answer, and then the usual Ok and Cancel buttons. I decided to add an icon to the dialog as well, for good looks. Here's the end result:

    A custom input dialog

    And here's the code for the dialog:

    <Window x:Class="WpfTutorialSamples.Dialogs.InputDialogSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="Input" SizeToContent="WidthAndHeight" WindowStartupLocation="CenterScreen"
            ContentRendered="Window_ContentRendered">
        <Grid Margin="15">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
    
            <Image Source="/WpfTutorialSamples;component/Images/question32.png" Width="32" Height="32" Grid.RowSpan="2" Margin="20,0" />
    
            <Label Name="lblQuestion" Grid.Column="1">Question:</Label>
            <TextBox Name="txtAnswer" Grid.Column="1" Grid.Row="1" MinWidth="250">Answer</TextBox>
    
            <WrapPanel Grid.Row="2" Grid.ColumnSpan="2" HorizontalAlignment="Right" Margin="0,15,0,0">
                <Button IsDefault="True" Name="btnDialogOk" Click="btnDialogOk_Click" MinWidth="60" Margin="0,0,10,0">_Ok</Button>
                <Button IsCancel="True" MinWidth="60">_Cancel</Button>
            </WrapPanel>
        </Grid>
    </Window>
    
    using System;
    using System.Windows;
    
    namespace WpfTutorialSamples.Dialogs
    {
    	public partial class InputDialogSample : Window
    	{
    		public InputDialogSample(string question, string defaultAnswer = "")
    		{
    			InitializeComponent();
    			lblQuestion.Content = question;
    			txtAnswer.Text = defaultAnswer;
    		}
    
    		private void btnDialogOk_Click(object sender, RoutedEventArgs e)
    		{
    			this.DialogResult = true;
    		}
    
    		private void Window_ContentRendered(object sender, EventArgs e)
    		{
    			txtAnswer.SelectAll();
    			txtAnswer.Focus();
    		}
    
    		public string Answer
    		{
    			get { return txtAnswer.Text; }
    		}
    	}
    }
    

    The code is pretty simple, but here are the things that you should pay special attention to:

    XAML

    In the XAML part, I've used a Grid for layout of the controls - nothing fancy here. I've removed the Width and Height properties of the Window and instead set it to automatically resize to match the content - this makes sense in a dialog, so you don't have to fine tune the size to make everything look alright. Instead, use margins and minimum sizes to ensure that things look the way you want them to, while still allowing the user to resize the dialog.

    Another property which I've changed on the Window is the WindowStartupLocation property. For a dialog like this, and probably for most other non-main windows, you should change this value to CenterScreen or CenterOwner, to change the default behavior where your window will appear in a position decided by Windows, unless you manually specify Top and Left properties for it.

    Also pay special attention to the two properties I've used on the dialog buttons: IsCancel and IsDefault. IsCancel tells WPF that if the user clicks this button, the DialogResult of the Window should be set to false which will also close the window. This also ensures that the user can press the Esc key on their keyboard to close the window, something that should always be possible in a Windows dialog.

    The IsDefault property gives focus to the Ok button and also ensures that if the user presses the Enter key on their keyboard, this button is activated. An event handler is needed to set the DialogResult for this though, as described later.

    Code-behind

    In Code-behind, I changed the constructor to take two parameters, with one being optional. This allows us to place the question and the default answer, if provided, into the designated UI controls.

    The Ok button has an event handler which ensures that the special DialogResult property of the Window is set to true when clicked, to signal to the initiator of the dialog that the user accepted the entered value. We don't have one for the Cancel button, because WPF handles this for us when we set the IsCancel property to true, as described above.

    To give focus to the TextBox upon showing the dialog, I've subscribed to the ContentRendered event, where I select all the text in the control and then give focus. If I just wanted to give focus, I could have use the FocusManager.FocusedElement attached property on the Window, but in this case, I also want to select the text, to allow the user to instantly overwrite the answer provided by default (if any).

    A last detail is the Answer property which I've implemented. It simply gives access to the entered value of the TextBox control, but it's good practice to provide a property with the return value(s) of the dialog, instead of directly accessing controls from outside the window. This also allows you to influence the return value before returning it, if needed.

    Using the dialog

    With all the above in place, we're now ready to actually use our dialog. It's a very simple task, so I've created a small application for testing it. Here's the code:

    <Window x:Class="WpfTutorialSamples.Dialogs.InputDialogAppSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="InputDialogAppSample" Height="150" Width="300">
        <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
            <TextBlock>Hello, world. My name is:</TextBlock>
            <TextBlock Name="lblName" Margin="0,10" TextAlignment="Center" FontWeight="Bold">[No name entered]</TextBlock>
            <Button Name="btnEnterName" Click="btnEnterName_Click">Enter name...</Button>
        </StackPanel>
    </Window>
    
    using System;
    using System.Windows;
    
    namespace WpfTutorialSamples.Dialogs
    {
    	public partial class InputDialogAppSample : Window
    	{
    		public InputDialogAppSample()
    		{
    			InitializeComponent();
    		}
    
    		private void btnEnterName_Click(object sender, RoutedEventArgs e)
    		{
    			InputDialogSample inputDialog = new InputDialogSample("Please enter your name:", "John Doe");
    			if(inputDialog.ShowDialog() == true)
    				lblName.Text = inputDialog.Answer;
    		}
    	}
    }
    

    A test application for our custom input dialog

    There's nothing special to it - just a couple of TextBlock controls and a Button for invoking the dialog. In the Click event handler, we instantiate the InputDialogSample window, providing a question and a default answer, and then we use the ShowDialog() method to show it - you should always use ShowDialog() method and not just Show() for a modal dialog like this.

    If the result of the dialog is true, meaning that the user has activated the Ok button either by clicking it or pressing Enter, the result is assigned to the name Label. That's all there is to it!

    advertise here!!!
  • Common Interface Controls ↓

    WPF Menu control

    advertise here!!!

    One of the most common parts of a Windows application is the menu, sometimes referred to as the main menu because only one usually exists in the application. The menu is practical because it offers a lot of options, using 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.

    WPF comes with a fine control for creating menus called... Menu. Adding items to it is very simple - you simply add MenuItem elements to it, and each 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:

    <Window x:Class="WpfTutorialSamples.Common_interface_controls.MenuSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MenuSample" Height="200" Width="200">
        <DockPanel>
            <Menu DockPanel.Dock="Top">
                <MenuItem Header="_File">
                    <MenuItem Header="_New" />
                    <MenuItem Header="_Open" />
                    <MenuItem Header="_Save" />
                    <Separator />
                    <MenuItem Header="_Exit" />
                </MenuItem>
            </Menu>
            <TextBox AcceptsReturn="True" />
        </DockPanel>
    </Window>
    

    A simple WPF Menu sample

    As in most Windows applications, my menu is placed in the top of the window, but in keeping with the enormous flexibility of WPF, you can actually place a Menu control wherever you like, and in any width or height that you may desire.

    I have defined a single top-level item, with 4 child items and a separator. I 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 use that character as the accelerator key, which means that the user can press the Alt key followed by the given character, to activate the menu item. This works all the way from the top-level item and down the hierarchy, meaning that in this example I could press Alt, then F and then N, to activate the New item.

    Icons and checkboxes

    Two common features of a menu item is the icon, used to more easily identify 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:

    <Window x:Class="WpfTutorialSamples.Common_interface_controls.MenuIconCheckableSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MenuIconCheckableSample" Height="150" Width="300">
        <DockPanel>
            <Menu DockPanel.Dock="Top">
                <MenuItem Header="_File">
                    <MenuItem Header="_Exit" />
                </MenuItem>
                <MenuItem Header="_Tools">
                    <MenuItem Header="_Manage users">
                        <MenuItem.Icon>
                            <Image Source="/WpfTutorialSamples;component/Images/user.png" />
                        </MenuItem.Icon>
                    </MenuItem>
                    <MenuItem Header="_Show groups" IsCheckable="True" IsChecked="True" />
                </MenuItem>
            </Menu>
            <TextBox AcceptsReturn="True" />
        </DockPanel>
    </Window>
    

    A WPF Menu control with checkable items and icons

    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 to allow the user to check and uncheck the item. I even used the IsChecked property to have it checked by default. From Code-behind, this is the same property that you can read to know whether a given menu item is checked or not.

    Handling clicks

    When the user clicks on a menu item, you will usually want something to happen. The easiest way is to simply add a click event handler to the MenuItem, like this:

    <MenuItem Header="_New" Click="mnuNew_Click" />
    

    In Code-behind you will then need to implement the mnuNew_Click method, like this:

    private void mnuNew_Click(object sender, RoutedEventArgs e)
    {
    	MessageBox.Show("New");
    }
    

    This will suffice for the more simple applications, or when prototyping something, but the WPF way is to use a Command for this.

    Keyboard shortcuts and Commands

    You can easily handle the Click event of a menu item like we did above, but the more common approach is to use WPF commands. There's a lot of theory on using and creating commands, so they have their own category of articles here on the site, but for now, I can tell you that they have a couple of advantages when used in WPF, especially in combination with a Menu or a Toolbar.

    First of all, they ensure that you can have the same action on a toolbar, a 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 will have to do that manually.

    However, when using commands, WPF is all ears and will respond to 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 used to invoke the specific menu item. Let's jump straight to an example of combining the Menu with WPF commands:

    <Window x:Class="WpfTutorialSamples.Common_interface_controls.MenuWithCommandsSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MenuWithCommandsSample" Height="200" Width="300">
        <Window.CommandBindings>
            <CommandBinding Command="New" CanExecute="NewCommand_CanExecute" Executed="NewCommand_Executed" />
        </Window.CommandBindings>
        <DockPanel>
            <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>
    
            <TextBox AcceptsReturn="True" Name="txtEditor" />
        </DockPanel>
    </Window>
    
    using System;
    using System.Windows;
    using System.Windows.Input;
    
    namespace WpfTutorialSamples.Common_interface_controls
    {
    	public partial class MenuWithCommandsSample : Window
    	{
    		public MenuWithCommandsSample()
    		{
    			InitializeComponent();
    		}
    
    		private void NewCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
    		{
    			e.CanExecute = true;
    		}
    
    		private void NewCommand_Executed(object sender, ExecutedRoutedEventArgs e)
    		{
    			txtEditor.Text = "";
    		}
    	}
    }
    
    

    A WPF Menu using commands

    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 items depending on the active control and its state. In this case, Cut and Copy are disabled because no text is selected, but Paste is enabled, because my clipboard is not empty!

    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.



    WPF ContextMenu

    A context menu, often referred to as a popup or pop-up menu, is a menu which is shown upon certain user actions, usually a right-click with the mouse on a specific control or window. Contextual menus are often used to offer 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 done through the ContextProperty, which all controls exposes (it comes from the FrameworkElement which most WPF controls inherits from). Consider the next example to see how it's done:

    <Window x:Class="WpfTutorialSamples.Common_interface_controls.ContextMenuSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="ContextMenuSample" Height="250" Width="250">
        <Grid>
            <Button Content="Right-click me!" VerticalAlignment="Center" HorizontalAlignment="Center">
                <Button.ContextMenu>
                    <ContextMenu>
                        <MenuItem Header="Menu item 1" />
                        <MenuItem Header="Menu item 2" />
                        <Separator />
                        <MenuItem Header="Menu item 3" />
                    </ContextMenu>
                </Button.ContextMenu>
            </Button>
        </Grid>
    </Window>
    

    A simple ContextMenu example

    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 handle when the user clicks on them, but a more WPF-suitable way is to use Commands.

    ContextMenu with Commands and icons

    In this next example, I'm going to show you two key concepts when using the ContextMenu: The usage of WPF Commands, which will provide us with lots of functionality including a Click event handler, a text and a shortcut text, simply by assigning something to the Command property. I will also show you to use icons on your ContextMenu items. Have a look:

    <Window x:Class="WpfTutorialSamples.Common_interface_controls.ContextMenuWithCommandsSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="ContextMenuWithCommandsSample" Height="200" Width="250">
        <StackPanel Margin="10">
            <TextBox Text="Right-click here for context menu!">
                <TextBox.ContextMenu>
                    <ContextMenu>
                        <MenuItem Command="Cut">
                            <MenuItem.Icon>
                                <Image Source="/WpfTutorialSamples;component/Images/cut.png" />
                            </MenuItem.Icon>
                        </MenuItem>
                        <MenuItem Command="Copy">
                            <MenuItem.Icon>
                                <Image Source="/WpfTutorialSamples;component/Images/copy.png" />
                            </MenuItem.Icon>
                        </MenuItem>
                        <MenuItem Command="Paste">
                            <MenuItem.Icon>
                                <Image Source="/WpfTutorialSamples;component/Images/paste.png" />
                            </MenuItem.Icon>
                        </MenuItem>
                    </ContextMenu>
                </TextBox.ContextMenu>
            </TextBox>
        </StackPanel>
    </Window>
    

    A ContextMenu with commands and icons

    Try running the example and see for yourself how much functionality we get for free by assigning commands to the items. Also notice how fairly simple it is to use icons on the menu items of the ContextMenu.

    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 ContextMenu property. However, in some situations, you might very well want to invoke it manually from code. This is pretty easy as well, so let's re-use the first example to demonstrate it with:

    <Window x:Class="WpfTutorialSamples.Common_interface_controls.ContextMenuManuallyInvokedSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="ContextMenuManuallyInvokedSample" Height="250" Width="250">
        <Window.Resources>
            <ContextMenu x:Key="cmButton">
                <MenuItem Header="Menu item 1" />
                <MenuItem Header="Menu item 2" />
                <Separator />
                <MenuItem Header="Menu item 3" />
            </ContextMenu>
        </Window.Resources>
        <Grid>
            <Button Content="Click me!" VerticalAlignment="Center" HorizontalAlignment="Center" Click="Button_Click" />
        </Grid>
    </Window>
    
    using System;
    using System.Windows;
    using System.Windows.Controls;
    
    namespace WpfTutorialSamples.Common_interface_controls
    {
    	public partial class ContextMenuManuallyInvokedSample : Window
    	{
    		public ContextMenuManuallyInvokedSample()
    		{
    			InitializeComponent();
    		}
    
    		private void Button_Click(object sender, RoutedEventArgs e)
    		{
    			ContextMenu cm = this.FindResource("cmButton") as ContextMenu;
    			cm.PlacementTarget = sender as Button;
    			cm.IsOpen = true;
    		}
    	}
    }
    

    A manually invoked ContextMenu

    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!



    WPF ToolBar control

    The toolbar is a row of commands, usually sitting right below the main menu of a standard Windows application. This could in fact be a simple panel with buttons on it, but by using the WPF ToolBar control, you get some extra 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 ToolBarTray will handle stuff like placement and sizing, and you can have multiple ToolBar controls inside of the ToolBarTray element. Let's try a pretty basic example, to see what it all looks like:

    <Window x:Class="WpfTutorialSamples.Common_interface_controls.ToolbarSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="ToolbarSample" Height="200" Width="300">
        <Window.CommandBindings>
            <CommandBinding Command="New" CanExecute="CommonCommandBinding_CanExecute" />
            <CommandBinding Command="Open" CanExecute="CommonCommandBinding_CanExecute" />
            <CommandBinding Command="Save" CanExecute="CommonCommandBinding_CanExecute" />
        </Window.CommandBindings>
        <DockPanel>
            <ToolBarTray DockPanel.Dock="Top">
                <ToolBar>
                    <Button Command="New" Content="New" />
                    <Button Command="Open" Content="Open" />
                    <Button Command="Save" Content="Save" />
                </ToolBar>
                <ToolBar>
                    <Button Command="Cut" Content="Cut" />
                    <Button Command="Copy" Content="Copy" />
                    <Button Command="Paste" Content="Paste" />
                </ToolBar>
            </ToolBarTray>
            <TextBox AcceptsReturn="True" />
        </DockPanel>
    </Window>
    
    using System;
    using System.Windows;
    using System.Windows.Input;
    
    namespace WpfTutorialSamples.Common_interface_controls
    {
    	public partial class ToolbarSample : Window
    	{
    		public ToolbarSample()
    		{
    			InitializeComponent();
    		}
    
    		private void CommonCommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
    		{
    			e.CanExecute = true;
    		}
    	}
    }
    

    A simple WPF ToolBar control

    Notice how I use commands for all the buttons. We discussed this in the previous chapter and using commands definitely gives us some advantages. Take a look at the Menu chapter, or the articles on commands, for more information.

    In this example, I add a ToolBarTray to the top of the screen, and inside of it, two ToolBar controls. Each contains some buttons and we use commands to give them their behavior. In Code-behind, I make sure to handle the CanExecute event of the first three buttons, since that's not done automatically by WPF, contrary to the Cut, Copy and Paste commands, which WPF is capable of fully handling for us.

    Try running the example and place the cursor over the left part of one of the toolbars (the dotted area). If you click and hold your left mouse button, you can now re-position the toolbar, e.g. below the other or even make them switch place.

    Images

    While text on the toolbar buttons is perfectly okay, the normal approach is to 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:

    <Window x:Class="WpfTutorialSamples.Common_interface_controls.ToolbarIconSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="ToolbarIconSample" 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>
            <TextBox AcceptsReturn="True" />
        </DockPanel>
    </Window>
    

    A WPF ToolBar with icons

    By specifying an Image control as the Content of the first two buttons, they will be icon based instead of text based. On the third button, I combine an Image control and a TextBlock control inside of a StackPanel, to achieve both icon and text on the button, a commonly used technique for buttons which are extra important or with a less obvious icon.

    Notice how I've used the ToolTip property on each of the buttons, to add an explanatory text. This is especially important for those buttons with only an icon, because the purpose of the button might not be clear from only looking at the icon. With the ToolTip property, the user can hover the mouse over the button to get a description of what it does, as demonstrated on the screenshot.

    Overflow

    As already mentioned, a very good reason for using the ToolBar control instead of just a panel of buttons, is the automatic overflow handling. It means that if there's no longer enough room to show all of the buttons on the toolbar, WPF will put them in a menu accessible by clicking on the arrow to the right of the toolbar. You can see how it works on this screenshot, which shows the first example, but with a smaller window, thereby leaving less space for the toolbars:

    A WPF ToolBar showing off the overflow functionality

    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.ToolbarPositionSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            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>
    

    WPF ToolBars in various positions

    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.ToolbarCustomControlsSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            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>
    

    A WPF ToolBar with custom controls

    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.



    WPF StatusBar control

    With the top of the application window usually occupied by the main menu and/or toolbars, described in previous chapters, the bottom part of the window is usually the home of the status bar. The status bar is used to show 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.

    Let's start off with a very basic example:

    <Window x:Class="WpfTutorialSamples.Common_interface_controls.StatusBarSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="StatusBarSample" Height="150" Width="300">
    	<DockPanel>
    		<StatusBar DockPanel.Dock="Bottom">
    			<StatusBarItem>
    				<TextBlock Name="lblCursorPosition" />
    			</StatusBarItem>
    		</StatusBar>
    		<TextBox AcceptsReturn="True" Name="txtEditor" SelectionChanged="txtEditor_SelectionChanged" />
    	</DockPanel>
    </Window>
    
    using System;
    using System.Windows;
    
    namespace WpfTutorialSamples.Common_interface_controls
    {
    	public partial class StatusBarSample : Window
    	{
    		public StatusBarSample()
    		{
    			InitializeComponent();
    		}
    
    		private void txtEditor_SelectionChanged(object sender, RoutedEventArgs e)
    		{
    
    			int row = txtEditor.GetLineIndexFromCharacterIndex(txtEditor.CaretIndex);
    			int col = txtEditor.CaretIndex - txtEditor.GetCharacterIndexFromLineIndex(row);
    			lblCursorPosition.Text = "Line " + (row + 1) + ", Char " + (col + 1);
    		}
    	}
    }
    

    A simple WPF StatusBar control

    It's all very simple - a TextBlock control that shows the current cursor 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 comes when we need to divide it into several areas of information.

    Advanced StatusBar example

    Let's try a more advanced example of using the StatusBar. The first thing we want to do is to make the StatusBar use another panel for the layout. By default, it uses the DockPanel, but when we want a more complex layout, with columns that adjusts its width in a certain way and aligned content, the Grid is a much better choice.

    We'll divide the Grid into three areas, with the left and right one having a fixed width and the middle column automatically taking up the remaining space. We'll also add columns in between for Separator controls. Here's how it looks now:

    <Window x:Class="WpfTutorialSamples.Common_interface_controls.StatusBarAdvancedSample"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="StatusBarAdvancedSample" Height="150" Width="400">
        <DockPanel>
            <StatusBar DockPanel.Dock="Bottom">
                <StatusBar.ItemsPanel>
                    <ItemsPanelTemplate>
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="100" />
                                <ColumnDefinition Width="Auto" />
                                <ColumnDefinition Width="*" />
                                <ColumnDefinition Width="Auto" />
                                <ColumnDefinition Width="100" />
                            </Grid.ColumnDefinitions>
                        </Grid>
                    </ItemsPanelTemplate>
                </StatusBar.ItemsPanel>
                <StatusBarItem>
                    <TextBlock Name="lblCursorPosition" />
                </StatusBarItem>
                <Separator Grid.Column="1" />
                <StatusBarItem Grid.Column="2">
                    <TextBlock Text="c:\path\of\current\file.txt" />
                </StatusBarItem>
                <Separator Grid.Column="3" />
                <StatusBarItem Grid.Column="4">
                    <ProgressBar Value="50" Width="90" Height="16" />
                </StatusBarItem>
            </StatusBar>
            <TextBox AcceptsReturn="True" Name="txtEditor" SelectionChanged="txtEditor_SelectionChanged" />
        </DockPanel>
    </Window>
    
    using System;
    using System.Windows;
    
    namespace WpfTutorialSamples.Common_interface_controls
    {
    	public partial class StatusBarAdvancedSample : Window
    	{
    		public StatusBarAdvancedSample()
    		{
    			InitializeComponent();
    		}
    
    		private void txtEditor_SelectionChanged(object sender, RoutedEventArgs e)
    		{
    			int row = txtEditor.GetLineIndexFromCharacterIndex(txtEditor.CaretIndex);
    			int col = txtEditor.CaretIndex - txtEditor.GetCharacterIndexFromLineIndex(row);
    			lblCursorPosition.Text = "Line " + (row + 1) + ", Char " + (col + 1);
    		}
    	}
    }
    

    A more advanced WPF StatusBar control sample

    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.



    Ribbon control

    The Ribbon interface was invented by Microsoft and first used in Office 2007. It combines the original menu and toolbar(s) into one control, with various functions grouped into tabs and groups. The most important purpose was to 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.

    The Ribbon, here in MS Word

    WPF doesn't come with a built-in Ribbon control, but Microsoft has released 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.

    Summary

    You can download and use a Microsoft created Ribbon control, but it's not yet a part of the .NET framework by default. Once it becomes an integrated part of the framework, we'll dig into it here at this tutorial. In the meantime, if 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.

Read More...