Walkthrough: Building a Simple WPF Application with the WPF Designer

This walkthrough shows how to build a simple Windows Presentation Foundation (WPF) application with the WPF Designer.

In this walkthrough, you perform the following tasks:

  • Create the project.

  • Create the layout.

  • Add controls to the layout.

  • Set layout-related properties.

  • Create a data source.

  • Connect to a data source.

  • Bind control properties.

When you are finished, you will have a simple application which lets you browse the file system. Your application's user interface will be implemented in Extensible Application Markup Language (XAML). For more information, see XAML in WPF. The following illustration shows how your application will appear.

FolderExplorer tree view and list views

Note

A hands-on lab version of this walkthrough that runs inside of Visual Studio 2010 is available at WPF Simple Application Walkthrough Hands on Lab.

Prerequisites

You need the following components to complete this walkthrough:

  • Visual Studio 2010.

Creating the Project

The first step is to create the project for the application.

To create the project

  1. Create a new WPF Application project in Visual Basic or Visual C# named FolderExplorer. For more information, see How to: Create a New WPF Application Project.

    MainWindow.xaml opens in the WPF Designer.

  2. In Design view, select the window. For more information, see How to: Select and Move Elements on the Design Surface.

  3. In the Properties window, set the value of the Title property to Folder Explorer.

Creating the Layout

The layout defines how controls are arranged in your application's main window. The following steps show how to construct layout elements which will contain the application's controls.

To create the layout

  1. Select the root Grid control on the window.

  2. Add a second row to the grid. For more information, see How to: Add Rows and Columns to a Grid.

  3. Add a second column to the grid.

Adding Controls to the Layout

With the layout defined, you can populate it with controls.

To add controls to the layout

  1. From the Toolbox, drag a TreeView control into the first cell of the grid.

  2. From the Toolbox, drag a ListView control into the cell occupying the first row and second column of the grid.

  3. From the Toolbox, drag a ListView control into the cell occupying the second row and second column of the grid.

The following steps show how to set layout-related properties on the controls. As you set properties on each control, the layout will more closely resemble the final application.

  1. Select the TreeView control.

  2. In the Properties window, set the following properties as shown.

    Property

    Value

    Grid.ColumnSpan

    1

    Grid.RowSpan

    2

    Height

    Auto

    HorizontalAlignment

    Stretch

    Margin

    0,0,0,0

    VerticalAlignment

    Stretch

    Width

    Auto

    The TreeView control resizes to fit in the first grid column and to span the two grid rows.

  3. Select both ListView controls.

  4. In the Properties window, set the following properties as shown.

    Property

    Value

    Grid.ColumnSpan

    1

    Grid.RowSpan

    1

    Height

    Auto

    HorizontalAlignment

    Stretch

    Margin

    0,0,0,0

    VerticalAlignment

    Stretch

    Width

    Auto

    The ListView controls resize to fit in their respective grid cells.

    Layout in Design view

  5. Open the Document Outline window. For more information, see Navigating the Element Hierarchy of a WPF Document.

  6. Expand the ColumnDefinitions node for the grid.

  7. Select the first ColumnDefinition item.

    Document Outline window

  8. In the Properties window, set the Width property to *.

  9. In the Document Outline window, select the second ColumnDefinition.

  10. In the Properties window, set the Width property to 2*.

    The columns are resized with the first column taking one-third of the window's width and the second column taking two-thirds.

  11. In the Document Outline window, expand the RowDefinitions node for the grid.

  12. Select the first RowDefinition item.

  13. In the Properties window, set the Height property to *.

  14. In the Document Outline window, select the second RowDefinition.

  15. In the Properties window, set the Height property to *.

    The rows resize to occupy half the window's height.

  16. Build and run the solution.

  17. Resize the window to see the TreeView and ListView controls dynamically resizing.

Creating a Data Source

The data source for the FolderExplorer application is a class named Folder. This class provides a simple model of the file system. Each Folder instance has a SubFolders and a Files collection.

To create a data source

  1. Add a new class named Folder to the FolderExplorer project. For more information, see How to: Add New Project Items.

  2. Replace the contents of the Folder source code file with the following code.

    Imports System
    Imports System.IO
    Imports System.Linq
    Imports System.Collections.Generic
    Imports System.Collections.ObjectModel
    Imports System.Text
    
    Public Class Folder
        Private _folder As DirectoryInfo
        Private _subFolders As ObservableCollection(Of Folder)
        Private _files As ObservableCollection(Of FileInfo)
    
        Public Sub New() 
            Me.FullPath = "c:\"
    
        End Sub 'New
    
    
        Public ReadOnly Property Name() As String 
            Get
                Return Me._folder.Name
            End Get
        End Property
    
    
        Public Property FullPath() As String 
            Get
                Return Me._folder.FullName
            End Get
    
            Set
                If Directory.Exists(value) Then
                    Me._folder = New DirectoryInfo(value)
                Else
                    Throw New ArgumentException("must exist", "fullPath")
                End If
            End Set
        End Property
    
        ReadOnly Property Files() As ObservableCollection(Of FileInfo)
            Get
                If Me._files Is Nothing Then
                    Me._files = New ObservableCollection(Of FileInfo)
    
                    Dim fi As FileInfo() = Me._folder.GetFiles()
    
                    Dim i As Integer
                    For i = 0 To fi.Length - 1
                        Me._files.Add(fi(i))
                    Next i
                End If
    
                Return Me._files
            End Get
        End Property
    
        ReadOnly Property SubFolders() As ObservableCollection(Of Folder)
    
            Get
                If Me._subFolders Is Nothing Then
                    Try
    
                    Me._subFolders = New ObservableCollection(Of Folder)
    
                        Dim di As DirectoryInfo() = Me._folder.GetDirectories()
    
                        Dim i As Integer
                        For i = 0 To di.Length - 1
                            Dim newFolder As New Folder()
                            newFolder.FullPath = di(i).FullName
                            Me._subFolders.Add(newFolder)
                        Next i
                    Catch ex As Exception
    
                        System.Diagnostics.Trace.WriteLine(ex.Message)
    
                    End Try
                End If
    
                Return Me._subFolders
            End Get
        End Property
    End Class
    
    using System;
    using System.IO;
    using System.Linq;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Text;
    
    namespace FolderExplorer
    {
        public class Folder
        {
            private DirectoryInfo _folder;
            private ObservableCollection<Folder> _subFolders;
            private ObservableCollection<FileInfo> _files;
    
            public Folder()
            {
                this.FullPath = @"c:\";
            }
    
            public string Name
            {
                get
                {
                    return this._folder.Name;
                }
            }
    
            public string FullPath
            {
                get
                {
                    return this._folder.FullName;
                }
    
                set
                {
                    if (Directory.Exists(value))
                    {
                        this._folder = new DirectoryInfo(value);
                    }
                    else
                    {
                        throw new ArgumentException("must exist", "fullPath");
                    }
                }
            }
    
            public ObservableCollection<FileInfo> Files
            {
                get
                {
                    if (this._files == null)
                    {
                        this._files = new ObservableCollection<FileInfo>();
    
                        FileInfo[] fi = this._folder.GetFiles();
    
                        for (int i = 0; i < fi.Length; i++)
                        {
                            this._files.Add(fi[i]);
                        }
                    }
    
                    return this._files;
                }
            }
    
            public ObservableCollection<Folder> SubFolders
            {
                get
                {
                    if (this._subFolders == null)
                    {
                        this._subFolders = new ObservableCollection<Folder>();
    
                        DirectoryInfo[] di = this._folder.GetDirectories();
    
                        for (int i = 0; i < di.Length; i++)
                        {
                            Folder newFolder = new Folder();
                            newFolder.FullPath = di[i].FullName;
                            this._subFolders.Add(newFolder);
                        }
                    }
    
                    return this._subFolders;
                }
            }
        }
    }
    

Connecting to a Data Source

WPF controls are connected to data sources through data binding. The following procedure shows how to declare and bind to an ObjectDataProvider.

To connect to a data source

  1. Open MainWindow.xaml in the WPF Designer. 

  2. In XAML view, insert the following XAML into the <Window> tag, with the other xmlns mappings. For more information, see How to: Import a Namespace into XAML.

    xmlns:my="clr-namespace:FolderExplorer"
    
  3. Insert the following XAML after the opening <Window> tag and before the opening <Grid> tag.

        <Window.Resources>
    
            <ObjectDataProvider x:Key="RootFolderDataProvider" >
                <ObjectDataProvider.ObjectInstance>
                    <my:Folder FullPath="c:\"/>
                </ObjectDataProvider.ObjectInstance>
            </ObjectDataProvider>
    
            <HierarchicalDataTemplate 
                DataType    = "{x:Type my:Folder}"
                ItemsSource = "{Binding Path=SubFolders}">
                <TextBlock Text="{Binding Path=Name}" />
            </HierarchicalDataTemplate>
    
        </Window.Resources>
    
    
  4. Replace the <TreeView> tag with the following XAML.

            <TreeView Grid.ColumnSpan="1" Grid.RowSpan="2" Margin="0,0,0,0" Name="treeView1" >
                <TreeViewItem ItemsSource="{Binding Path=SubFolders, Source={StaticResource RootFolderDataProvider}}" Header="Folders"  />
            </TreeView>
    

Binding Control Properties

You can bind a control's properties to another control, which enables automatic property updating.

To bind control properties

  1. In XAML view, replace both <ListView> tags with the following XAML.

            <ListView Name="listView1" 
            ItemsSource="{Binding Path=SelectedItem.SubFolders, ElementName=treeView1, Mode=OneWay}" 
            Grid.Column="1" 
            Grid.RowSpan="1" />
    
            <ListView Name="listView2" 
            ItemsSource="{Binding Path=SelectedItem.Files, ElementName=treeView1, Mode=OneWay}" 
            Grid.Column="1" 
            Grid.Row="1" />
    
  2. Build and run the solution.

  3. Expand the Folders item to see folders from your C: drive.

  4. Experiment by clicking subfolders and observing the contents of the two ListView controls.

    Subfolders are displayed in the upper ListView control and files are displayed in the lower ListView control.

Next Steps

  • Currently, the FolderExplorer application is displayed with the default styling. You can apply your own styles to change the application's appearance and behavior.

  • Visual Studio also provides many tools for debugging your WPF application. For more information, see Walkthrough: Debugging WPF Custom Controls at Design Time.

See Also

Tasks

How to: Use Attached Events

Walkthrough: Debugging WPF Custom Controls at Design Time

Concepts

Split View: Viewing the WPF Design Surface and XAML at the Same Time

Navigating the Element Hierarchy of a WPF Document

Other Resources

Working with Controls in the WPF Designer