Absolute Beginner's Guide to WPF Application With Examples

Discussion in 'C#' started by shabbir, May 4, 2014.

  1. shabbir

    shabbir Administrator Staff Member

    Joined:
    Jul 12, 2004
    Messages:
    15,375
    Likes Received:
    388
    Trophy Points:
    83
    WPF (Windows Presentation Foundation) is a Microsoft’s technology for creating rich client applications. WPF applications are more interactive, aesthetic and flexible as compared to their traditional counter parts The Windows Form applications. WPF is a subset of Microsoft’s famous .NET framework.

    WPF brought a landmark change in the Microsoft’s graphic rendering techniques. With WPF the graphics rendered to the user screens are vector based and are resolution independent. WPF has all what it takes to build and deploy a stunning client application including data binding capability, rich user controls, media, document, styles, texts, animation and typography.

    WPF applications allow user to separate appearance and user interface logic from the code behind. This is similar to ASP.NET where web page and the code behind files are separate. In WPF, the appearance and front end is handled by the XAML (Extensible Markup Language) and the back end is handled by any managed programming language such as C# or VB.

    WPF Example for Beginners!



    To further understand how actually WPF applications work and how the front end and the code behind files integrate with each other, have a look at the first example of this article.
    Follow these steps to create simple WPF application with a window and one button on it. When the button is clicked a dialogue box appears which displays some message.
    1. Open Visual Studio 2010 or above and click on New Project.
    2. Choose WPF application as a template. It is under C# option on the left side of the visual studio (See following figure). Give it any name (WPFTutorial in my case) and click ok button.
      [​IMG]
    3. A new WPF project would be created. In the project solution section. You will find a file named MainWindow.xaml and if you click on the small triangle left to this file, you will see MainWindow.xaml.cs file. The MainWindow.xaml is the front end file that contains the user interface logic and MainWindow.xaml.cs is the file that contains code behind logic.

    The user interface

    If you click and open the MainWindow.xaml file in visual studio, it will be opened by default in split mode showing design at the top and the corresponding XAML code in the bottom. The XAML code looks like this:
    Code:
    <Window x:Class="WPFTutorial.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>
    
    There are two XAML elements in the above code, Window and Grid. Window is the top level element and Grid is the element which contains controls such as buttons, fields etc. Remember that there can be only one top level window in any WPF application. Apart from Window element, Page and Application are the other two top level elements.

    Each element in the WPF XAML file or the user interface file corresponds to a class. For instance in the above code, Window element refers to a class derived from Window class located in in System.Windows name space. The Window element contains several attributes such as Title, Height and Width. These are actually the properties of the Window class which is inherited by our Window element in the above code. The Window element contains following lines:
    Code:
    x:Class="WPFTutorial.MainWindow"
    
    x:Class element specifies the code behind file for this MainWindow.xaml class. In the above lines, it is specified that the code behind file which controls the event and back end logic is MainWindow class in the WPFTutorial namespace.

    The Code Behind

    Now if you open the file MainWindow.xaml.cs (The code behind file), you will find the following code there:
    Code:
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    
    namespace WPFTutorial
    {
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
        }
    }
    
    It is evident that the namespace WPFTutorial contains a partial class MainWindow which inherits from the Window class. This code behind class contains a default constructor which contains InitializeComponent method. For now, just remember that InitializeComponent method is responsible for initializing all the controls on the UI class and it also binds the UI class to the code behind class. It is automatically added to the constructor of the code behind file when a new UI or XAML file is generated.

    Adding two numbers in a WPF application



    Till now, we have been only talking about what WPF applications are and what is its salient feature. To see how things actually work in action, let us add two numbers provided by the users. The WPF Grid element will contain 2 Label controls, 3 TextBox Controls and 1 Button control. Drag and drop these elements from the toolbox on to the MainWindow.xaml designer from the last example. The designer should look like the one in the following figure:

    [​IMG]

    To change the properties of each control on the control panel, you simply have to click on the control and change its values in the Properties window of the visual studio.

    Change the Content property of the upper label to Number1 and the lower label to Number2. Change the Name property of the upper TextBox control (next to Label ‘Number1’) to tb_num1 and Change its Text property to empty. Similarly, Change the Name property of the middle TextBox control (next to Label ‘Number2’) to tb_num2 and also make its Text property empty. Change the name property of the Button control which you added to btn_sum and change its Content property to Sum. Finally Change the Name property of the last TextBox control (next to Button control) to tb_result and make its Text property empty. The resultant designer window should look like the one in the above example.

    Note that the controls we added were via visual studio’s drag and drop feature. You can also manually add these features to the corresponding xaml file. In fact when the controls are dragged and dropped on the designer window, actually the corresponding xaml file is also being updated. Now if you open the code of your MainWindow.xaml file. You will see the following markup.
    Code:
    <Window x:Class="WPFTutorial.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="385.821" Width="653.358">
        <Grid>
            <TextBox x:Name="tb_num1" HorizontalAlignment="Left" Height="23" Margin="142,51,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" RenderTransformOrigin="0.431,0.546"/>
            <Label Content="Number1" HorizontalAlignment="Left" Margin="48,45,0,0" VerticalAlignment="Top" Width="94"/>
            <Label Content="Number2" HorizontalAlignment="Left" Margin="48,76,0,0" VerticalAlignment="Top"/>
            <TextBox x:Name="tb_num2" HorizontalAlignment="Left" Height="23" Margin="142,79,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
            <Button x:Name="btn_sum" Content="Sum" HorizontalAlignment="Left" Margin="48,107,0,0" VerticalAlignment="Top" Width="60" Click="Button_Click_1"/>
            <TextBox x:Name="tb_result" HorizontalAlignment="Left" Height="23" Margin="142,107,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" />
        </Grid>
    </Window>
    
    It can be seen that all the controls that have been added are encapsulated as elements inside the Grid element. The order of the newly added elements depends upon the control that was added first. For instance, in the above example, the TextBox control with Name property tb_num1 was added first, therefore it appears at the first element inside the parent Grid element.

    It is also worth noticing that the properties of the controls appear as attributes of the corresponding elements. For instance, we changed the Content property of labels, it can be seen the labels element contains Content attribute which contains the same value as we specified for its Content property. If the values are changed in XAML code, you would see that they would also be modified in the visual studios property windows.

    We want that the sum of the values entered by the user in the top 2 TextBox controls should be displayed in the third TextBox control, when user clicks on Sum button.

    To add an event handler which executes when the btn_sum is clicked, the Click event should be added. This is done by giving any name to the Click event in the visual studio’s event window. To see the events associated with a control, click on the event icon that is located inside the Properties window. Give the name “btn_sum_click” to the Click event of btn_sum button. You would see that a new attribute:
    Code:
    Click="btn_sum_click
    
    It would be added to the Button element of the xaml code. Similarly, the following event handler will also be added to code behind MainWindows.xaml.cs file:
    Code:
    private void btn_sum_click(object sender, RoutedEventArgs e)
    {
    
    }
    
    Now all the addition and result displaying logic has to be written inside this event handler. Modify the above event handler as follows:
    Code:
    private void btn_sum_click(object sender, RoutedEventArgs e)
    {
        int result = Int32.Parse(tb_num1.Text) + Int32.Parse(tb_num2.Text);
        tb_result.Text = result.ToString();
    }
    
    Basically in the event handler, we are parsing the text values entered in the tb_num1 and tb_num2 TextBox controls to Int32. We stored these values in the result variable. We then changed the Text property of the tb_result TextBox control to result variable, by converting the result variable to string. The output of the above program is shown in the following figure:

    [​IMG]

    See how smooth the output window is and how nicely the controls are arranged. This is just a glimpse of what we can achieve with a more complex WPF application.

    Working with WPF Layouts



    Organizing elements and controls in a desired manner is probably one of the most laborious tasks while developing rich client applications such as WPF. In WPF applications GUI is not dependent upon the physical resolution of the system which results in uniform display of WPF application GUI on systems with various resolutions. WPF applications are also capable of adapting itself gracefully to changing window sizes.

    Before dwelling into the details of the layouts in WPF, following are some of the important points that must be kept in mind:
    • The Window and other top level elements can contain only one control. To add multiple controls to a WPF application a container is required.
    • The element should be added inside a container in such a way that they are automatically resized depending on the content.
    • Unlike Windows form based applications, control in WPF applications should be arranged based on the container in which they are placed, instead of coordinates based system.
    Remember that all the layouts in WPF are actually derived from System.Windows.Controls.Panel class and they are themselves a panel.

    The StackPanel Layout



    The StackPanel layout is one of the simplest layouts in WPF. This layout arranges elements in a single row or single column. To see the working of StackPanel layout, modify the code of MainWindow.xaml window created earlier in this tutorial, as follows:
    Code:
    <Window x:Class="WPFTutorial.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="300" Width="400">
        <StackPanel>
            <Label> Top to bottom stack panel</Label>
            <Button>First button</Button>
            <Button>Second button</Button>
            <Button>Third button</Button>
            <Button>Fourth button</Button>
        </StackPanel>
    </Window>
    
    Now, if you look into the designer or if you run your program, you will see the following output window:

    [​IMG]

    By default, the label and four button controls have been added in the top to bottom manner and the width of buttons is stretched enough to fit the width of the panel. Real magic begins when you resize the above window. You will see that the button controls will shrink and expand depending upon the size of the window. The height of the label and button controls would be set appropriately by the StackPanel to fit the text in the child controls.

    Similarly, to arrange controls in left to right order (horizontally). The Orientation attribute of the StackPanel is set to Horizontal. The following code explains how horizontal arrangement of elements can be achieved in StackPanel!
    Code:
    <Window x:Class="WPFTutorial.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="300" Width="400">
        
        <StackPanel Orientation="Horizontal">
            <Label> Top to bottom stack panel</Label>
            <Button>First button</Button>
            <Button>Second button</Button>
            <Button>Third button</Button>
            <Button>Fourth button</Button>
        </StackPanel>
    </Window>
    
    Now, if you compile the above code and see the resultant window, it would look like this:

    [​IMG]

    This is not we desire because the StackPanel allotted the space required to display the text of label and buttons to each control which resulted in the fourth button being shifted outside the window sized. If window is resized towards right, this element would appear. However, there are certain properties that can be used to change the behavior of individual elements.

    Aligning Elements

    The elements in a container can be aligned both vertically and horizontally by using HorizontalAlignment and VerticalAlignment property. For instance in the following code, the label and four buttons in MainWindow.xaml file have been aligned using HorizontalAlignment property. Since the orientation of the StackPanel is vertical, therefore there is no need to set vertical alignment. Have a look at the following code:
    Code:
    <Window x:Class="WPFTutorial.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="300" Width="400">
        
        <StackPanel >
            <Label HorizontalAlignment="Left"> Top to bottom stack panel</Label>
            <Button HorizontalAlignment="Right">First button</Button>
            <Button HorizontalAlignment="Left">Second button</Button>
            <Button HorizontalAlignment="Center">Third button</Button>
            <Button>Fourth button</Button>
        </StackPanel> 
    </Window>
    
    Inside the StackPanel element, it can be seen that HorizontalAlignment attribute has been added to the label and first three buttons. Label would be aligned left, First button is aligned right, and Second button is aligned left, third button is aligned center and the Fourth button has the default alignment which is stretch by default. If the above code is compiled and run, the following output window would be displayed:

    [​IMG]

    Setting Margins

    Another very important property of elements in a container is that of Margin which is used to set margin between the elements. To see how margins actually work, consider the following code snippets:
    Code:
    <Window x:Class="WPFTutorial.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="300" Width="400">
        
        <StackPanel >
            <Label > Top to bottom stack panel</Label>
            <Button Margin="7">First button</Button>
            <Button  Margin="7">Second button</Button>
            <Button  Margin="7">Third button</Button>
            <Button Margin="20,10,50,10">Fourth button</Button>
    
        </StackPanel>
    </WIndow>
    
    In the above code xaml file, First, Second and Third button have a margin of 7 from left, top, right and bottom. To specify single values for all the sides a single integer is specified for the Margin attribute. However, if different values are to be assigned for the Margin attribute then 4 values are entered separated by comma as in case of fourth button in the above code sample where Margin =”20, 10, 50, 10” attribute is used. Here 20 is the left margin, 10 is the top margin, 50 is the right margin and 10 is the bottom margin.

    MaxWidth/MinWidth and MaxHeight/MinHeight Properties

    It is never a good Idea in a WPF application to specify explicit heights and widths of the elements inside a container. Rather, the MaxWidth/MinWidth and MaxHeight/MinHeight values should be specified. The MaxWidth denotes the maximum width of the element when windows expanded whereas the MinWidth denotes the minimum width of the element irrespective of how much the window is contracted. The following code snippet shows how these maximum and minimum values can be used in an application:
    Code:
    <Window x:Class="WPFTutorial.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="300" Width="400" MinWidth="150">
        
        <StackPanel Margin="20">
            <Label > Top to bottom stack panel</Label>
            <Button Margin="7" MaxWidth="200" MinWidth ="65">First button</Button>
            <Button  Margin="7" MaxWidth="200" MinWidth ="65">Second button</Button>
            <Button  Margin="7" MaxWidth="200" MinWidth ="65">Third button</Button>
            <Button Margin="7" MaxWidth="200" MinWidth ="65">Fourth button</Button>
        </StackPanel>
    </Window>
    
    A MinWidth attribute of Window element is set to 150 which means that though the absolute Width of the Window element has been specified as 400, the width cannot be made smaller than 150 when windows is resized. Similarly, all the buttons contains a sMaxWidth attribute of 200 and MinWidth attribute of 65. If the above code is compiled, following window appears:

    [​IMG]

    If the above Window is resized, you will see that its width will not be decreased more than certain limit, similarly the widths of the buttons will be decreased to a certain limit only. This is due to the fact that their MinWidth and MaxWidth properties have been set.

    Using Borders

    Borders are not panel or containers they are used inside outside panels to border a group of elements inside the panel. For instance to insert a border for the four buttons in the MainWindow.xaml, the following code can be used:
    Code:
    <Window x:Class="WPFTutorial.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="300" Width="400" MinWidth="150">
    
            <Border Margin="10" Background="RoyalBlue" BorderBrush="Black" BorderThickness="5" CornerRadius="5" Padding="5">
            <StackPanel>
             <Button Margin="7" MaxWidth="200" MinWidth ="65">First button</Button>
            <Button  Margin="7" MaxWidth="200" MinWidth ="65">Second button</Button>
            <Button  Margin="7" MaxWidth="200" MinWidth ="65">Third button</Button>
            <Button Margin="7" MaxWidth="200" MinWidth ="65">Fourth button</Button>
            </StackPanel>
        </Border> 
    </Window>
    
    Border element has several important attributes as shown in the above code. The Background attribute sets the background color, the BorderBrush sets the color of the border, BorderThickness sets thickness of the border CornerRadius is used to slightly round the borders at the corners. If the above code is compiled, the following output would be displayed:

    [​IMG]

    It can be seen that a black border has appeared around the panel with round borders at the corners and a margin of 10 of all sides from the outer element.

    The WrapPanel Layout



    The StackPanel layout could only contain one element per row or per column. The WrapPanel contains multiple elements in a row or column depending upon the amount of space available. To see, how WrapPanel actually works, take a look at the following xaml code.
    Code:
    <Window x:Class="WPFTutorial.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="300" Width="400" MinWidth="150">
        
            <WrapPanel>
            <Button VerticalAlignment="Center" >First button</Button>
            <Button MinHeight="70">Second button</Button>
            <Button  VerticalAlignment="Bottom">Third button</Button>
            <Button  VerticalAlignment="Top">Fourth button</Button>
            <Button  VerticalAlignment="Bottom">Fifth button</Button>
        </WrapPanel>
    </Window>
    
    By default, the WrapPanel insert elements horizontally from left to right and then it switches to the next row again adding elements from left to right. In the above code, the height of the second button is set to a minimum value of 70. The remaining buttons will be vertically aligned with respect to this height. For instance third button is bottom aligned, it will be aligned to the bottom of the second button, and similarly fourth button is Top aligned it will be aligned to the Top of the second button. The output window of the above code will look like this:

    [​IMG]

    Similarly, to vertically add element in a WrapPanel, the Orientation attribute of the WrapPanel must be set to Vertical. This is shown in the following code:
    Code:
    <Window x:Class="WPFTutorial.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="300" Width="400" MinWidth="150">
    
            <WrapPanel Orientation="Vertical">
            <Button HorizontalAlignment="Center" >First button</Button>
            <Button MinWidth="150">Second button</Button>
            <Button  HorizontalAlignment="Right">Third button</Button>
            <Button  HorizontalAlignment="Left">Fourth button</Button>
            <Button HorizontalAlignment="Right">Fourth button</Button>
        </WrapPanel>
    </Window>
    
    Note that the width of the column will be the width of the widest element in the panel. In the above code, the width of the first column of WrapPanel would be 150 i.e. the width of the Second button. All the remaining buttons in the first column would be aligned with respect to this width. The output window will look like this:

    [​IMG]

    In this article the basics of WPF applications have been explained along with two basic layout types: The StackPanel and Wrap layouts. Apart from these two layouts, DockPanel and Grid layouts are most widely used which are the subjects of our next tutorial. Keep visiting this website.
     
    Last edited: Jan 21, 2017

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice