WPF cheat sheet
A scannable WPF reference: 18 short snippets across 10 topics, each linking back to the lesson it came from.
At a glance
| Topic | What it covers | |
|---|---|---|
| Data binding | A binding connects a target property on a dependency object to a source property. The source is normally resolved | lesson |
| MVVM basics and commands | MVVM splits a screen into a model (data and rules), a view-model (state and behaviour for one screen) and a view (XAML | lesson |
| Resources, styles, templates and themes | Keep raw values - colours, sizes, corner radii - in one dictionary, and reference them from styles and templates. A | lesson |
| Items controls, collections and virtualization | The default view is shared per collection. If two independent controls must filter the same source differently, wrap | lesson |
| Validation, converters and input handling | Use StringFormat for display-only formatting - {Binding Total, StringFormat={}{0:C}} is cheaper and shorter than a | lesson |
| Navigation, windows and dialogs | For a multi-view application, either set a single ContentControl whose content is the current view model, or use a | lesson |
| Asynchronous work and UI responsiveness | await on the dispatcher, Task.Run for CPU work, progress and cancellation, dispatcher priorities, and how to keep a | lesson |
| Animation and visual states | States are the right model for a reusable control: the control decides which state it is in, and the template decides | lesson |
| 2D graphics, shapes and transforms | Shapes versus drawings, Geometry and Path, brushes and gradients, render transforms, and rendering a visual to a bitmap | lesson |
| WPF performance and testing MVVM applications | A view model built on interfaces can be tested in milliseconds with no window, no dispatcher and no application | lesson |
Quick snippets
Data binding
Converters and formatting
<Window.Resources>
<local:BoolToVisibilityConverter x:Key="BoolToVis" />
<local:MoneyConverter x:Key="Money" />
<BooleanToVisibilityConverter x:Key="BuiltInBoolToVis" />
</Window.Resources>
<TextBlock Text="{Binding Total, Converter={StaticResource Money}}" />
<Border Visibility="{Binding HasError, Converter={StaticResource BoolToVis}}" />
MVVM basics and commands
ICommand and RelayCommand
<Button Content="Save"
Command="{Binding SaveCommand}" />
<Button Content="Delete"
Command="{Binding DeleteCommand}"
CommandParameter="{Binding SelectedItem, ElementName=OrderGrid}" />
<ListBox x:Name="OrderGrid" ItemsSource="{Binding Orders}" />Full lesson: MVVM basics and commands →
Resources, styles, templates and themes
Resource lookup order
<Window.Resources>
<SolidColorBrush x:Key="Accent">#2F6FED</SolidColorBrush>
<sys:Double x:Key="Gap" xmlns:sys="clr-namespace:System;assembly=System.Runtime">12</sys:Double>
</Window.Resources>
<StackPanel>
<TextBlock Text="Total" Foreground="{StaticResource Accent}" />
<Border Background="{DynamicResource PanelBackground}" />
</StackPanel>
ControlTemplate and DataTemplate
<!-- theme dictionaries loaded at startup -->
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Themes/Colors.Light.xaml" />
<ResourceDictionary Source="pack://application:,,,/Themes/Controls.xaml" />
</ResourceDictionary.MergedDictionaries>Full lesson: Resources, styles, templates and themes →
Items controls, collections and virtualization
Grouping, sorting and filtering
var view = CollectionViewSource.GetDefaultView(Orders);
view.SortDescriptions.Add(new SortDescription(nameof(Order.Date), ListSortDirection.Descending));
view.GroupDescriptions.Add(new PropertyGroupDescription(nameof(Order.Region)));
view.Filter = o => ((Order)o).Total >= _minTotal;
// a filter change must be announced or the view looks frozen
view.Refresh();
// and the collection itself must notify for the view to follow
public ObservableCollection<Order> Orders { get; } = new();
Grouping, sorting and filtering
<ListBox ItemsSource="{Binding Orders}">
<ListBox.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock FontWeight="Bold" Margin="0,8,0,2"
Text="{Binding Name}" />
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListBox.GroupStyle>
</ListBox>
Staying smooth
// batch changes so the UI updates once instead of once per item
using (Orders.DeferRefresh())
{
foreach (var order in loaded)
Orders.Add(order);
}
// when the list is rebuilt often, hand over a finished collection instead
OnPropertyChanged(nameof(Orders));Full lesson: Items controls, collections and virtualization →
Validation, converters and input handling
Three validation mechanisms
<TextBox Text="{Binding Customer, UpdateSourceTrigger=PropertyChanged, ValidatesOnNotifyDataErrors=True}" />
<Button Content="Save"
IsEnabled="{Binding HasErrors, Converter={StaticResource InverseBool}}" />
Converters and formatting
<!-- StringFormat, not a converter, for simple display formatting -->
<TextBlock Text="{Binding Total, StringFormat={}{0:N2}}" />
<!-- the built-in converter for booleans -->
<Button IsEnabled="{Binding IsEditable}" Visibility="{Binding IsEditable, Converter={StaticResource BoolToVisibility}}" />Full lesson: Validation, converters and input handling →
Navigation, windows and dialogs
Windows and modal dialogs
// the dialog stays in front, and we read the result afterwards
var dialog = new CustomerEditWindow { Owner = this, DataContext = new CustomerEditViewModel(id) };
if (dialog.ShowDialog() == true)
await _orders.ReloadAsync();
// and inside the dialog
private void OnSave(object sender, RoutedEventArgs e)
{
if (!_viewModel.Validate()) return;
DialogResult = true; // also closes the window
}Full lesson: Navigation, windows and dialogs →
Asynchronous work and UI responsiveness
CPU work, progress and cancellation
// update a chart at most ~30 times a second instead of on every data point
private readonly DispatcherTimer _render = new() { Interval = TimeSpan.FromMilliseconds(33) };
public App()
{
_render.Tick += (s, e) => { Render(_pending); };
}
Dispatcher priorities and frozen windows
// let the current layout finish before scrolling or focusing
Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(() =>
{
Results.ScrollIntoView(Results.SelectedItem);
}));
// keep a background read off the critical path
await Dispatcher.InvokeAsync(() =>
{
Status = "Ready";
}, DispatcherPriority.Background);Full lesson: Asynchronous work and UI responsiveness →
Animation and visual states
VisualStateManager
// a control drives its own states from code
protected override void OnIsEnabledChanged(DependencyPropertyChangedEventArgs e)
{
base.OnIsEnabledChanged(e);
VisualStateManager.GoToState(this, IsEnabled ? "Normal" : "Disabled", useTransitions: true);
}
Reduced motion and perceived speed
// read the OS preference once at startup and keep the whole app consistent
private static bool ReducedMotion =>
SystemParameters.ClientAreaAnimation == false ||
SystemParameters.MenuAnimation == false;
if (!ReducedMotion)
Storyboard.Begin(this);Full lesson: Animation and visual states →
2D graphics, shapes and transforms
Shapes and geometry
<Canvas Width="200" Height="120">
<Rectangle Canvas.Left="10" Canvas.Top="10" Width="80" Height="50"
Fill="#2F6FED" RadiusX="6" RadiusY="6" />
<Ellipse Canvas.Left="110" Canvas.Top="10" Width="60" Height="60" Stroke="Gray" StrokeThickness="2" />
<!-- Polyline: an open figure. Polygon: closed and filled. -->
<Polyline Points="10,90 40,70 70,100 100,60" Stroke="SeaGreen" StrokeThickness="2" />
<!-- Path with a geometry mini-language: M move, L line, C curve, Z close -->
<Path Data="M 120 90 C 140 60, 170 120, 190 80 Z"
Fill="#EED46A" Stroke="#B08300" StrokeThickness="1.5" />
</Canvas>
Shapes and geometry
<!-- frozen and reused is far cheaper than recreated per item -->
<Path Data="{StaticResource WarningIcon}"
Fill="{StaticResource AccentBrush}"
Stretch="Uniform" Width="16" Height="16" />Full lesson: 2D graphics, shapes and transforms →
WPF performance and testing MVVM applications
Testing view models
// anything that touches the dispatcher needs it while testing
[Fact]
public void Save_command_raises_property_changed()
{
var raised = new List<string>();
var vm = new EditorViewModel();
vm.PropertyChanged += (s, e) => raised.Add(e.PropertyName);
vm.SaveCommand.Execute(null);
Assert.Contains(nameof(EditorViewModel.IsDirty), raised);
}
When to add UI automation
<Button Content="Save"
AutomationProperties.AutomationId="SaveButton"
AutomationProperties.Name="Save the order"
Command="{Binding SaveCommand}" />Full lesson: WPF performance and testing MVVM applications →
FAQ
Is this WPF cheat sheet free to use?
Where do the examples come from?
How do I go deeper than a cheat sheet?
Related cheat sheets
.NET ASP.NET Core LINQ WinForms
Last refreshed 2026-09-27.