whitespace COMPANY whitespace SERVICES whitespace PRODUCTS whitespace PURCHASE whitespace SUPPORT whitespace CONTACTS whitespace Home whitespace Contact Us whitespace Site Map whitespace
whitespace
WHY ARTFULBITS
whitespace
OUR APPROACH
whitespace
OUR TEAM
whitespace
FACT SHEET
whitespace
NEWS & EVENTS
whitespace
PRIVACY
whitespace
whitespace

My first WPF application

Downloads

Project archive


In this article we will examine how to create a simple WPF application. Let it be a calculator with basic functionality. Call it "WPFCalculator".


This we are going to get in the end.

What you need

In order to develop WPF applications on Windows XP SP2 or Windows Vista we need to install:

  1. Visual Studio 2005
  2. .NET Framework 3.0 Redistributable Package (also known as the Runtime Components) from here. (you do not need to do this step if you're running Windows Vista because the .NET Framework 3.0 is an intrinsic part of Vista)
  3. Windows WinFX SDK from here. This installs a ton of help content (samples, documentation, etc) and some great tools, like XamlPad.
  4. Microsoft Visual Studio 2005 extensions, from here. This installs Project and Items Templates for Visual Studio so that you can create WinFX projects.

Lets begin

First of all we have to create a new WPF project. After we installed all WPF components, in VisualStudio "New Project" dialog we can see some new project templates, marked with "Avalon" emblem (green gun shield).

Lets select "WinFX Windows Application", type the name and you will get a new empty project. In accordance with a new WPF strategy our application is divided in to branches: visual presentation (file with extension .xaml) and "code behind" (.xaml.cs).

In Window1.xaml we will create a feature GUI of our calculator. Since in VisualStudio there is no designer for WPF yet, we have to do it manually. Don't be frightened, it is very easy and interesting. For this things we have a XAML - Extensible Application Markup Language (pronounced as "zammel").

XAML is a declarative XML-based language that defines objects and their properties in XML. XAML syntax describes objects, properties and their relationships to one another. Generic XAML syntax defines the relationship between objects and children. Properties can be set as attributes or by using 'period notation' to specify the object as a property of its parent.

For example:

<object>  
  <child property="x" property="y">      
    <child.property>           
      <class property="u" property="v"/>      
    </child.property>   
  </child>   
  <child x="y" u="v"/> 
</object>

You ask why XAML is so cool? First of all because controls became more extensible and flexible than WinForms. For example, if you want your button to have 3 images side by side, with text going diagonally across the images, you can that very easy. Not only for buttons, most controls allow this feature. The "content" area of button or other controls allow only one child, but once that child is a panel (or another layout control), you can add there almost everything you want . In XAML you can also set styles, which makes building of a consistent but complicated GUI comparatively easy, use powerful mechanism of data binding, or even write an amusing animation in a three lines. So, I think XAML gives more freedom for our fantasy, staying very simple for understanding.

GUI

As I already said, visual part of our calculator is located in "Window1.xaml" file. For proper work of our application this file should have the following view:

<Window x:Class="WPWCalculator.Window1" 
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
  Title="WPFCalculator" Height="300"
  Width="300" Background="WhiteSmoke">
  <Grid Width="200" Height="150" Background="LightBlue">
    <Grid.RowDefinitions>
      <RowDefinition />
      <RowDefinition />
      <RowDefinition />
      <RowDefinition />
      <RowDefinition />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
      <ColumnDefinition />
      <ColumnDefinition />
      <ColumnDefinition />
      <ColumnDefinition />
      <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <TextBox Name="txtResult" Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="5" Height="20"
      Margin="4" TextAlignment="Right" IsReadOnly="True" />
    <Button Click="OnButton7Click" Grid.Column="0" Grid.Row="1" Margin="4" Content="7" />
    <Button Click="OnButton4Click" Grid.Column="0" Grid.Row="2" Margin="4" Content="4" />
    <Button Click="OnButton1Click" Grid.Column="0" Grid.Row="3" Margin="4" Content="1" />
    <Button Click="OnButton0Click" Grid.Column="0" Grid.Row="4" Margin="4" Content="0" />
    <Button Click="OnButton8Click" Grid.Column="1" Grid.Row="1" Margin="4" Content="8" />
    <Button Click="OnButton5Click" Grid.Column="1" Grid.Row="2" Margin="4" Content="5" />
    <Button Click="OnButton2Click" Grid.Column="1" Grid.Row="3" Margin="4" Content="2" />
    <Button Click="OnButton9Click" Grid.Column="2" Grid.Row="1" Margin="4" Content="9" />
    <Button Click="OnButton6Click" Grid.Column="2" Grid.Row="2" Margin="4" Content="6" />
    <Button Click="OnButton3Click" Grid.Column="2" Grid.Row="3" Margin="4" Content="3" />
    <Button Click="OnButtonFactClick" Grid.Column="2" Grid.Row="4" Margin="4" Content="n\!" />
    <Button Click="OnButtonDivClick" Grid.Column="3" Grid.Row="1" Margin="4" Content="/" />
    <Button Click="OnButtonMultClick" Grid.Column="3" Grid.Row="2" Margin="4" Content="*" />
    <Button Click="OnButtonSubClick" Grid.Column="3" Grid.Row="3" Margin="4" Content="-" />
    <Button Click="OnButtonAddClick" Grid.Column="3" Grid.Row="4" Margin="4" Content="+" />
    <Button Click="OnButtonChangeSignClick" Grid.Column="1" Grid.Row="4" Margin="4"
      Content="+/-" />
    <Button Click="OnButtonClearClick" Grid.Column="4" Grid.Row="1" Grid.RowSpan="2"
      Margin="4" Content="C" />
    <Button Click="OnButtonEqualClick" Grid.Column="4" Grid.Row="3" Grid.RowSpan="2"
      Margin="4" Content="=" />
  </Grid>
</Window>

As you can see we have the main object - <Window> and one "big child" - <Grid>. In WPF there are a lot of layout controls, such as Panel, StackPanel, DockPanel, Canvas or Viewbox but Grid is more convenient, as our calculator has cells-like structure. Isn't it true that XAML is easily understood? Almost everything is clear from the first glance. At first we proclaim a <Window> then we proclaim a <Grid> inside, saying how many columns and rows it should have, and like cells, we proclaim buttons, pointing its location inside Grid.

If you notice such properties as: Grid.Column, Grid.Row, Grid.ColumnSpan, Grid.RowSpan that set a location inside Grid, do not belong to the Button class. It's so-called attached properties - one of the WPF features. It's very useful because you can attach it anytime you need, binding two objects in that way.

Implementation

Now we begin to implement a logic for our WPFCalculator. At first we add a new class to the project. Inside the Solution Explorer right click on the WPFCalculator -> Add -> Existing Item... and open file "Calculator.cs" It can be downloaded from here. After that, a new file should appear in our project hierarchy.

This class encapsulates a calculating functionality of our WPFCalculator, so you don't need to concentrate your attention on it.

To make all this work,  we should also change a code behind file (Window1.xaml.cs). After some modifications it should look like this:

namespace WPWCalculator
{
  /// <summary>
  /// Interaction logic for Window1.xaml
  /// </summary>
  public partial class Window1 : System.Windows.Window
  {
    #region Private members
    /// <summary>
    /// Calculator object
    /// </summary>
    private Calculator m_Calc;
    #endregion

    #region Initialization
    public Window1()
    {
      InitializeComponent();

      m_Calc = new Calculator();

      txtResult.Text = m_Calc.Display();
    }

    #endregion

    #region Event handlers
    /// <summary>
    /// Executes on "0" button click.
    /// </summary>

    void OnButton0Click( object sender, RoutedEventArgs args )
    {
      m_Calc.AddDigit( 0 );

      txtResult.Text = m_Calc.Display();
    }
    /// <summary>
    /// Executes on "1" button click.
    /// </summary>
    void OnButton1Click( object sender, RoutedEventArgs args )
    {
      m_Calc.AddDigit( 1 );
      txtResult.Text = m_Calc.Display();
    }

    /// <summary>Executes on "2" button click.</summary>
    void OnButton2Click( object sender, RoutedEventArgs args )
    {
      m_Calc.AddDigit( 2 );
      txtResult.Text = m_Calc.Display();
    }
    /// <summary>Executes on "3" button click.</summary>

    void OnButton3Click( object sender, RoutedEventArgs args )
    {
      m_Calc.AddDigit( 3 );
      txtResult.Text = m_Calc.Display();
    }
    /// <summary>Executes on "4" button click.</summary>
    void OnButton4Click( object sender, RoutedEventArgs args )
    {
      m_Calc.AddDigit( 4 );
      txtResult.Text = m_Calc.Display();
    }
    /// <summary>Executes on "5" button click.</summary>
    void OnButton5Click( object sender, RoutedEventArgs args )
    {
      m_Calc.AddDigit( 5 );
      txtResult.Text = m_Calc.Display();
    }
    /// <summary>Executes on "6" button click.</summary>
    void OnButton6Click( object sender, RoutedEventArgs args )
    {
      m_Calc.AddDigit( 6 );
      txtResult.Text = m_Calc.Display();
    }
    /// <summary>Executes on "7" button click.</summary>
    void OnButton7Click( object sender, RoutedEventArgs args )
    {
      m_Calc.AddDigit( 7 );
      txtResult.Text = m_Calc.Display();
    }
    /// <summary>Executes on "8" button click.</summary>
    void OnButton8Click( object sender, RoutedEventArgs args )
    {
      m_Calc.AddDigit( 8 );
      txtResult.Text = m_Calc.Display();
    }
    /// <summary>Executes on "9" button click.</summary>
    void OnButton9Click( object sender, RoutedEventArgs args )
    {
      m_Calc.AddDigit( 9 );
      txtResult.Text = m_Calc.Display();
    }
    /// <summary>Executes on "=" button click.</summary>
    void OnButtonEqualClick( object sender, RoutedEventArgs args )
    {
      m_Calc.Calculate( Calculator.Operations.Equal );
      txtResult.Text = m_Calc.Display();
    }
    /// <summary>Executes on "/" button click.</summary>
    void OnButtonDivClick( object sender, RoutedEventArgs args )
    {
      m_Calc.Calculate( Calculator.Operations.Divide );
      txtResult.Text = m_Calc.Display();
    }
    /// <summary>Executes on "*" button click.</summary>
    void OnButtonMultClick( object sender, RoutedEventArgs args )
    {
      m_Calc.Calculate( Calculator.Operations.Multiply );
      txtResult.Text = m_Calc.Display();
    }
    /// <summary>Executes on "-" button click.</summary>
    void OnButtonSubClick( object sender, RoutedEventArgs args )
    {
      m_Calc.Calculate( Calculator.Operations.Subtract );
      txtResult.Text = m_Calc.Display();
    }
    /// <summary>Executes on "+" button click.</summary>
    void OnButtonAddClick( object sender, RoutedEventArgs args )
    {
      m_Calc.Calculate( Calculator.Operations.Add );
      txtResult.Text = m_Calc.Display();
    }
    /// <summary>Executes on "n\!" button click.</summary>
    void OnButtonFactClick( object sender, RoutedEventArgs args )
    {
      m_Calc.Factorial();
      txtResult.Text = m_Calc.Display();
    }
    /// <summary>Executes on "C" button click.</summary>
    void OnButtonClearClick( object sender, RoutedEventArgs args )
    {
      m_Calc.Clear();
      txtResult.Text = m_Calc.Display();
    }
    /// <summary>Executes on "+/-" button click.</summary>
    void OnButtonChangeSignClick( object sender, RoutedEventArgs args )
    {
      m_Calc.ChangeSign();
      txtResult.Text = m_Calc.Display();
    }
    #endregion
  }
}

Note that we don't have the definition of the click event handler in this generated class. For event handlers and other initialization and helpers, a XAML file is meant to be matched with a corresponding code-behind file, which is a .NET language code file that implements behavior "behind" the look defined in the XAML. Traditionally, this file is named with a .xaml.cs extension and contains only the things not defined in the XAML.
You may also notice that we no longer have a Main entry point to create the instance of the application-derived class and call its Run method. That's because WPF has a special project setting to specify the XAML file that defines the application class, which appears in the MSBuild project file.

We did it

Now you can bravely press F5 to run our application. I think everything is OK, and if you have done everything right WPFCalculator appeared on your screen.
I hope this small article showed you how easy it is to create WPF applications.


< Previous | Home | Next >


Author: 2007 Dima Zaharov, Department Manager/ArtfulBits
Company | Services | Practices | Technologies | Career | Contacts | Privacy
© 2005-2016 ArtfulBits. All rights reserved.