Skip to main content

.NET WPF Introduction

Windows Presentation Foundation (WPF) is a powerful UI framework for creating desktop applications with visually stunning user interfaces on Windows. If you're looking to build modern, feature-rich desktop applications with .NET, WPF is an excellent choice to explore.

What is Windows Presentation Foundation?

Windows Presentation Foundation (WPF) is a part of the .NET Framework that provides a unified programming model for building desktop applications with rich user interfaces. Introduced with .NET Framework 3.0 in 2006, WPF has evolved to be a robust platform for creating Windows desktop applications.

Key Features of WPF

  • XAML-based UI design: Separate UI design from business logic
  • Rich graphics support: Vector-based rendering for resolution independence
  • Data binding: Powerful connection between UI and data
  • Templates and styles: Easily customize and reuse UI elements
  • Animation and effects: Create dynamic and engaging interfaces
  • Hardware acceleration: Leverage GPU for faster performance

WPF vs. Windows Forms

Before WPF, Windows Forms was the primary UI framework for Windows desktop applications. Here's how they compare:

FeatureWPFWindows Forms
RenderingVector-based (resolution independent)Pixel-based
UI DescriptionXAML (declarative)C# code (imperative)
UI/Logic SeparationStrong separation (MVVM pattern)Limited separation
StylingRich styling systemBasic styling
3D SupportBuilt-inLimited
Hardware AccelerationYesNo

Getting Started with WPF

Let's create a simple "Hello World" WPF application to get started.

Required Tools

  • Visual Studio (Community edition or higher)
  • .NET SDK (Latest version recommended)
  • Basic understanding of C# programming

Creating Your First WPF Application

  1. Open Visual Studio
  2. Select "Create a new project"
  3. Search for "WPF App" and select "WPF Application" under C#
  4. Name your project "HelloWPF" and click "Create"

Visual Studio will generate two important files:

  • MainWindow.xaml: Contains UI in XAML format
  • MainWindow.xaml.cs: Contains C# code-behind for the window

Understanding the Basic Structure

Here's the default XAML generated when you create a new WPF application:

xml
<Window x:Class="HelloWPF.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:HelloWPF"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>

</Grid>
</Window>

This creates an empty window with a Grid layout container. The Window element is the root of a WPF window, and Grid is one of several layout containers in WPF.

Adding Content to the Window

Let's add some basic controls to our window:

xml
<Window x:Class="HelloWPF.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:HelloWPF"
mc:Ignorable="d"
Title="Hello WPF" Height="300" Width="400">
<StackPanel Margin="20">
<TextBlock Text="Hello, WPF!"
FontSize="24"
FontWeight="Bold"
Margin="0,0,0,20"/>
<TextBox x:Name="nameTextBox"
Margin="0,0,0,10"
PlaceholderText="Enter your name"/>
<Button Content="Say Hello"
Click="Button_Click"
Width="100"
HorizontalAlignment="Left"/>
<TextBlock x:Name="outputText"
Margin="0,20,0,0"
FontSize="16"/>
</StackPanel>
</Window>

Now let's add the logic in the code-behind file (MainWindow.xaml.cs):

csharp
using System.Windows;

namespace HelloWPF
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}

private void Button_Click(object sender, RoutedEventArgs e)
{
if (string.IsNullOrWhiteSpace(nameTextBox.Text))
{
outputText.Text = "Please enter your name.";
}
else
{
outputText.Text = $"Hello, {nameTextBox.Text}! Welcome to WPF.";
}
}
}
}

When you run this application, you'll see a window with:

  • A title "Hello, WPF!"
  • A text box where you can enter your name
  • A button labeled "Say Hello"
  • An area where a greeting will appear when you click the button

Understanding XAML

XAML (eXtensible Application Markup Language) is the declarative XML-based language used to define WPF user interfaces. It separates UI design from the application logic.

Key Concepts in XAML

Element Syntax

XAML elements correspond to .NET classes:

xml
<Button Content="Click Me" />

This creates an instance of the Button class and sets its Content property.

Property Attribute Syntax

Simple properties are set as attributes:

xml
<Button Content="Click Me" Width="100" Height="30" />

Property Element Syntax

Complex properties use property element syntax:

xml
<Button>
<Button.Content>
<StackPanel>
<Image Source="/Images/icon.png" Width="16" Height="16" />
<TextBlock Text="Click Me" />
</StackPanel>
</Button.Content>
</Button>

Content Syntax

For classes with a content property (usually Content), you can use simplified syntax:

xml
<Button>Click Me</Button>

WPF Layout Containers

WPF offers several layout containers to organize UI elements:

Grid

The most versatile layout panel, allowing elements to be positioned in rows and columns:

xml
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>

<Label Grid.Row="0" Grid.Column="0">Name:</Label>
<TextBox Grid.Row="0" Grid.Column="1" />

<Label Grid.Row="1" Grid.Column="0">Email:</Label>
<TextBox Grid.Row="1" Grid.Column="1" />
</Grid>

StackPanel

Arranges elements in a single line (horizontal or vertical):

xml
<StackPanel Orientation="Vertical">
<Button Content="Button 1" Margin="5" />
<Button Content="Button 2" Margin="5" />
<Button Content="Button 3" Margin="5" />
</StackPanel>

WrapPanel

Similar to StackPanel, but wraps elements to the next line when space runs out:

xml
<WrapPanel>
<Button Content="Button 1" Width="100" Margin="5" />
<Button Content="Button 2" Width="100" Margin="5" />
<Button Content="Button 3" Width="100" Margin="5" />
<Button Content="Button 4" Width="100" Margin="5" />
</WrapPanel>

DockPanel

Docks elements to the edges of the container:

xml
<DockPanel>
<Button DockPanel.Dock="Top" Content="Top" Height="50" />
<Button DockPanel.Dock="Left" Content="Left" Width="50" />
<Button DockPanel.Dock="Right" Content="Right" Width="50" />
<Button DockPanel.Dock="Bottom" Content="Bottom" Height="50" />
<TextBlock Text="Center Content" HorizontalAlignment="Center" VerticalAlignment="Center" />
</DockPanel>

Canvas

Provides absolute positioning of elements:

xml
<Canvas>
<Button Canvas.Left="10" Canvas.Top="10" Content="Button 1" />
<Button Canvas.Left="100" Canvas.Top="50" Content="Button 2" />
<Ellipse Canvas.Left="50" Canvas.Top="100" Width="100" Height="50" Fill="Blue" />
</Canvas>

Data Binding

One of the most powerful features of WPF is data binding, which connects UI elements with data sources.

Basic Data Binding

Let's create a simple data binding example:

xml
<Window x:Class="BindingDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Data Binding Demo" Height="200" Width="400">
<StackPanel Margin="10">
<TextBox x:Name="inputTextBox" Margin="0,0,0,10" />
<TextBlock Text="{Binding ElementName=inputTextBox, Path=Text}"
FontWeight="Bold" />
<Slider x:Name="slider" Minimum="0" Maximum="100"
Value="50" Margin="0,20,0,0" />
<TextBlock Text="{Binding ElementName=slider, Path=Value}"
FontWeight="Bold" />
</StackPanel>
</Window>

In this example:

  • The first TextBlock shows whatever you type in the TextBox
  • The second TextBlock displays the current value of the Slider

Binding to Custom Objects

For more complex scenarios, you can bind to custom objects:

csharp
// Person.cs
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public string FullName => $"{FirstName} {LastName}";
}
xml
<Window x:Class="BindingDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Data Binding Demo" Height="300" Width="400"
Loaded="Window_Loaded">
<StackPanel Margin="10">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>

<Label Grid.Row="0" Grid.Column="0">First Name:</Label>
<TextBox Grid.Row="0" Grid.Column="1"
Text="{Binding FirstName, UpdateSourceTrigger=PropertyChanged}" />

<Label Grid.Row="1" Grid.Column="0">Last Name:</Label>
<TextBox Grid.Row="1" Grid.Column="1"
Text="{Binding LastName, UpdateSourceTrigger=PropertyChanged}" />

<Label Grid.Row="2" Grid.Column="0">Age:</Label>
<TextBox Grid.Row="2" Grid.Column="1"
Text="{Binding Age, UpdateSourceTrigger=PropertyChanged}" />

<Label Grid.Row="3" Grid.Column="0">Full Name:</Label>
<TextBlock Grid.Row="3" Grid.Column="1" Text="{Binding FullName}" />
</Grid>
</StackPanel>
</Window>
csharp
// MainWindow.xaml.cs
public partial class MainWindow : Window
{
private Person _person;

public MainWindow()
{
InitializeComponent();
}

private void Window_Loaded(object sender, RoutedEventArgs e)
{
_person = new Person
{
FirstName = "John",
LastName = "Doe",
Age = 30
};

this.DataContext = _person;
}
}

Real-World Application Example

Let's create a simple task management application to demonstrate WPF in a real-world context:

xml
<Window x:Class="TaskManager.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Task Manager" Height="450" Width="600">
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>

<!-- Header -->
<StackPanel Grid.Row="0" Margin="0,0,0,10">
<TextBlock Text="Task Manager" FontSize="24" FontWeight="Bold"/>
<TextBlock Text="Manage your daily tasks efficiently" Opacity="0.6"/>
</StackPanel>

<!-- Task List -->
<ListView Grid.Row="1" x:Name="taskListView" Margin="0,0,0,10"
SelectionChanged="taskListView_SelectionChanged">
<ListView.View>
<GridView>
<GridViewColumn Header="Done" Width="50">
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsCompleted, Mode=TwoWay}"
Checked="CheckBox_Changed"
Unchecked="CheckBox_Changed"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Title" Width="200"
DisplayMemberBinding="{Binding Title}"/>
<GridViewColumn Header="Priority" Width="100"
DisplayMemberBinding="{Binding Priority}"/>
<GridViewColumn Header="Due Date" Width="150"
DisplayMemberBinding="{Binding DueDate, StringFormat='{}{0:MM/dd/yyyy}'}"/>
</GridView>
</ListView.View>
</ListView>

<!-- Add Task Form -->
<Grid Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>

<TextBox Grid.Column="0" x:Name="newTaskTextBox"
Margin="0,0,5,0" PlaceholderText="Enter new task..." />
<ComboBox Grid.Column="1" x:Name="priorityComboBox"
Width="100" Margin="0,0,5,0">
<ComboBoxItem Content="Low"/>
<ComboBoxItem Content="Medium" IsSelected="True"/>
<ComboBoxItem Content="High"/>
</ComboBox>
<DatePicker Grid.Column="2" x:Name="dueDatePicker"
Width="120" Margin="0,0,5,0"/>
<Button Grid.Column="3" Content="Add Task"
Click="AddTask_Click" Width="80"/>
</Grid>
</Grid>
</Window>
csharp
// Task.cs
public class Task
{
public string Title { get; set; }
public string Priority { get; set; }
public DateTime DueDate { get; set; }
public bool IsCompleted { get; set; }
}

// MainWindow.xaml.cs
using System;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;

namespace TaskManager
{
public partial class MainWindow : Window
{
private ObservableCollection<Task> _tasks;

public MainWindow()
{
InitializeComponent();

_tasks = new ObservableCollection<Task>();

// Add some example tasks
_tasks.Add(new Task { Title = "Learn WPF", Priority = "High", DueDate = DateTime.Now.AddDays(1) });
_tasks.Add(new Task { Title = "Complete project", Priority = "Medium", DueDate = DateTime.Now.AddDays(7) });
_tasks.Add(new Task { Title = "Read documentation", Priority = "Low", DueDate = DateTime.Now.AddDays(3) });

taskListView.ItemsSource = _tasks;

// Initialize date picker with today's date
dueDatePicker.SelectedDate = DateTime.Today;
}

private void AddTask_Click(object sender, RoutedEventArgs e)
{
if (string.IsNullOrWhiteSpace(newTaskTextBox.Text))
{
MessageBox.Show("Please enter a task title.", "Validation Error", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}

var newTask = new Task
{
Title = newTaskTextBox.Text,
Priority = ((ComboBoxItem)priorityComboBox.SelectedItem).Content.ToString(),
DueDate = dueDatePicker.SelectedDate ?? DateTime.Today,
IsCompleted = false
};

_tasks.Add(newTask);
newTaskTextBox.Clear();
}

private void CheckBox_Changed(object sender, RoutedEventArgs e)
{
// You can add logic here to handle task completion
}

private void taskListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
// You can add logic here to handle task selection
}
}
}

Summary

In this introduction to WPF, we've explored:

  • The basics of WPF and how it compares to Windows Forms
  • Creating a simple WPF application
  • Understanding XAML, the markup language for WPF
  • Working with various layout containers
  • Using data binding to connect UI to data
  • Building a real-world task management application

WPF provides a powerful platform for creating modern Windows desktop applications with rich user interfaces. Its separation of UI and logic through XAML and code-behind, along with features like data binding and templates, makes it an excellent choice for desktop application development.

Additional Resources

Practice Exercises

  1. Calculator Application: Create a simple calculator with buttons for digits and basic operations.

  2. Image Viewer: Build an application that allows users to browse and view images from a folder.

  3. Contact Manager: Develop a contact management application that stores contact information and allows searching and filtering.

  4. Weather App: Create an application that fetches and displays weather data for a selected location.

  5. Theme Switcher: Build a WPF application that allows users to switch between different visual themes (light/dark mode).



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)