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

TopicWhat it covers
Data bindingA binding connects a target property on a dependency object to a source property. The source is normally resolvedlesson
MVVM basics and commandsMVVM splits a screen into a model (data and rules), a view-model (state and behaviour for one screen) and a view (XAMLlesson
Resources, styles, templates and themesKeep raw values - colours, sizes, corner radii - in one dictionary, and reference them from styles and templates. Alesson
Items controls, collections and virtualizationThe default view is shared per collection. If two independent controls must filter the same source differently, wraplesson
Validation, converters and input handlingUse StringFormat for display-only formatting - {Binding Total, StringFormat={}{0:C}} is cheaper and shorter than alesson
Navigation, windows and dialogsFor a multi-view application, either set a single ContentControl whose content is the current view model, or use alesson
Asynchronous work and UI responsivenessawait on the dispatcher, Task.Run for CPU work, progress and cancellation, dispatcher priorities, and how to keep alesson
Animation and visual statesStates are the right model for a reusable control: the control decides which state it is in, and the template decideslesson
2D graphics, shapes and transformsShapes versus drawings, Geometry and Path, brushes and gradients, render transforms, and rendering a visual to a bitmaplesson
WPF performance and testing MVVM applicationsA view model built on interfaces can be tested in milliseconds with no window, no dispatcher and no applicationlesson

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}}" />

Full lesson: Data binding →

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?
Yes. No sign-up and no tracking: the page is static, every example is on the page itself, and you can print it or save it as a one-page reference.
Where do the examples come from?
Every snippet is taken from the 10 lessons of the WPF course on this site, and each section links back to the lesson it was pulled from.
How do I go deeper than a cheat sheet?
Open the full WPF course — it carries the worked explanations, the edge cases and the exercises behind every line here.

.NET ASP.NET Core LINQ WinForms

Last refreshed 2026-09-27.