Edit

Share via


How to create a data binding (WPF .NET)

This article describes how to create a binding XAML. The example uses a data object that represents an employee at a company. This data object is bound to a XAML window that uses TextBlock controls to list the employee's details. You'll create a UI that looks like the following image:

A WPF window that shows details about an employee, such as their first name, last name, title, hire date, and salary.

To learn more about data binding, see Data binding overview in WPF.

Create a data object

In this example, an employee is used as the data object that the UI is bound to.

  1. Add a new class to your project and name it Employee.

  2. Replace the code with the following snippet:

    using System;
    using System.ComponentModel;
    
    namespace ArticleSample
    {
        public class Employee : INotifyPropertyChanged
        {
            private decimal _salary;
            public event PropertyChangedEventHandler? PropertyChanged;
    
            public required string FirstName { get; set; }
            public required string LastName { get; set; }
            public required string Title { get; set; }
            public required DateTime HireDate { get; set; }
    
            public required decimal Salary
            {
                get => _salary;
                set
                {
                    _salary = value;
    
                    // Support TwoWay binding
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Salary)));
                }
            }
        }
    }
    
    Imports System.ComponentModel
    
    Public Class Employee
        Implements INotifyPropertyChanged
    
        Private _salary As Decimal
        Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
    
        Public Property FirstName As String
        Public Property LastName As String
        Public Property Title As String
        Public Property HireDate As DateTime
    
        Public Property Salary As Decimal
            Get
                Return _salary
            End Get
            Set(value As Decimal)
                _salary = value
                RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(NameOf(Salary)))
            End Set
        End Property
    
    End Class
    

The employee data object is a simple class that describes an employee:

  • The first and last name of the employee.
  • The date the employee was hired.
  • The employee's company title.
  • How much income the employee earns.

Bind to a data object

The following XAML demonstrates using the Employee class as a data object. The root element's DataContext property is bound to a static resource declared in the XAML. The individual controls are bound to the properties of the Employee.

  1. Add a new Window to the project and name it EmployeeView

  2. Replace the XAML with the following snippet:

    Important

    The following snippet is taken from a C# project. If you're using Visual Basic, the x:Class should be declared without the ArticleSample namespace. You can see what the Visual Basic version looks like here.

    <Window x:Class="ArticleSample.EmployeeView"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:ArticleSample"
            Title="" Height="250" Width="300">
        <Window.Resources>
            <local:Employee x:Key="EmployeeExample" FirstName="Niki" LastName="Demetriou"
                                                    HireDate="2022-02-16" Salary="5012.00"
                                                    Title="Content Artist" />
        </Window.Resources>
        <StackPanel DataContext="{StaticResource EmployeeExample}">
            <Label FontSize="32">Employee</Label>
            <Border BorderBrush="Gray" BorderThickness="2" />
            <Grid Grid.Row="1" Margin="5">
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
    
                <TextBlock Text="First Name:" Grid.Row="0" Margin="0,0,10,0" />
                <TextBlock Text="Last Name:" Grid.Row="1" />
                <TextBlock Text="Title:" Grid.Row="2" />
                <TextBlock Text="Hire Date:" Grid.Row="3" />
                <TextBlock Text="Salary" Grid.Row="4" />
    
                <TextBlock Text="{Binding FirstName}" Grid.Row="0" Grid.Column="1" />
                <TextBlock Text="{Binding LastName}" Grid.Row="1" Grid.Column="1" />
                <TextBlock Text="{Binding Title}" Grid.Row="2" Grid.Column="1" />
                <TextBlock Text="{Binding HireDate, StringFormat=d}" Grid.Row="3" Grid.Column="1" />
                <TextBlock Text="{Binding Salary, StringFormat=C0}" Grid.Row="4" Grid.Column="1" />
            </Grid>
            <Border BorderBrush="Gray" BorderThickness="2" />
            
            <StackPanel Margin="5,10" Orientation="Horizontal">
                <TextBlock Text="Change Salary:" Margin="0,0,10,0" />
                <TextBox Text="{Binding Salary, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, StringFormat=C0}" Width="100" />
            </StackPanel>
        </StackPanel>
    </Window>
    

The namespace of the code won't match your project's namespace, unless you created a project named ArticleSample. You can copy and paste the Window.Resources and root element (StackPanel) into you're MainWindow if you created a new project.

To better understand how the previous XAML is using data binding, consider the following points:

  • A XAML resource is used to create an instance of the Employee class.

    Typically the data object is passed to or associated with the Window. This example hardcodes the employee for demonstration purposes.

    <Window.Resources>
        <local:Employee x:Key="EmployeeExample" FirstName="Niki" LastName="Demetriou"
                                                HireDate="2022-02-16" Salary="5012.00"
                                                Title="Content Artist" />
    </Window.Resources>
    
  • The root element (StackPanel) has its data context set to the hardcoded Employee instance.

    The child elements inherit their DataContext from the parent, unless explicitly set.

    <StackPanel DataContext="{StaticResource EmployeeExample}">
    
  • The properties of the Employee instance are bound to the TextBlock controls.

    The Binding doesn't specify a BindingSource, so the DataContext is used as the source.

    <TextBlock Text="{Binding FirstName}" Grid.Row="0" Grid.Column="1" />
    <TextBlock Text="{Binding LastName}" Grid.Row="1" Grid.Column="1" />
    <TextBlock Text="{Binding Title}" Grid.Row="2" Grid.Column="1" />
    <TextBlock Text="{Binding HireDate, StringFormat=d}" Grid.Row="3" Grid.Column="1" />
    <TextBlock Text="{Binding Salary, StringFormat=C0}" Grid.Row="4" Grid.Column="1" />
    
  • A TextBox control is bound with TwoWay mode, allowing the TextBox to change the Employee.Salary property.

    <TextBox Text="{Binding Salary, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, StringFormat=C0}" Width="100" />