Click here to Skip to main content
15,884,059 members
Articles / Desktop Programming / WPF

DataContext in WPF

Rate me:
Please Sign up or sign in to vote.
4.71/5 (30 votes)
30 Jan 2012CPOL4 min read 283.8K   41   7
The Binding object needs to get its data from somewhere, and there are a few ways to specify the source of the data like using Source property directly in the Binding, inheriting a DataContext from the nearest element...

DataContext

DataContext is one of the most fundamental concepts in Data Binding. The Binding object needs to get its data from somewhere, and there are a few ways to specify the source of the data like using Source property directly in the Binding, inheriting a DataContext from the nearest element when traversing up in the tree, setting the ElementName and RelativeSource properties in the Binding object.

User interface elements in WPF have a DataContext dependency property. That property has the aforementioned "value inheritance" feature enabled, so if you set the DataContext on an element to a Student object, the DataContext property on all of its logical descendant elements will reference that Student object too. This means that all data bindings contained within that root element’s element tree will automatically bind against the Student object, unless explicitly told to bind against something else. This feature is extremely useful while designing WPF applications. In the following example, we are setting the DataContext in the code and all the elements in the window get to access the Student object.

Exposing the Entire Object as DataContext from the Code

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace DataContextSample
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            Student objstudent = new Student();
            objstudent.StudentName = "Kishore1021";
            this.DataContext = objstudent;
        }
        public class Student
        {
            private string studentname;
            public string StudentName
            {
                get
                {
                    return studentname;
                }
                set
                {
                    studentname = value;
                }
            }
        }
    }
}

XAML for the above code

XML
<Window x:Class="DataContextSample.MainWindow"</li>
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"> </RowDefinition>
        </Grid.RowDefinitions>
        <TextBox Name="TextBox1" Text="{Binding Path=StudentName}"></TextBox>
    </Grid>
</Window>
  • Download the source code from Microsoft here

Exposing Just a Single Property Value from the Code

In the Student class, I added one more property Address. In the MainWindow, an Employee object is created and initialized with some values and we are setting just the address as the datacontext using this.DataContext = objstudent.Address; in line28:

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace DataContextSample
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            Student objstudent = new Student();
            objstudent.StudentName = "Kishore1021";
            objstudent.Address = "Washington DC";
            this.DataContext = objstudent.Address;
        }

        public class Student
        {
            private string studentname;
            private string address;

            public string Address
            {
                get { return address; }
                set { address = value; }
            }

            public string StudentName
            {
                get
                {
                    return studentname;
                }
                set
                {
                    studentname = value;
                }
            }
        }
    }
}

In the XAML code, I created two textblocks and assigned the address. Keep a watch on how I am using the DataContext values. Since we are just setting the Address as DataContext, TextBlock1 binding doesn’t know where to find in that address property. TextBlock2 binds to whatever is there in the datacontext, which is just the address property.

XML
<Window x:Class="DataContextSample.MainWindow" 
    xmlns="<a href="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
    http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="<a href="http://schemas.microsoft.com/winfx/2006/xaml">
    http://schemas.microsoft.com/winfx/2006/xaml</a>" 
    Title="MainWindow" Height="350" Width="525">
  • Download the source code from here

To Understand the above concept better, see the following code. I have an employee class and one more class called AnotherClass and used employee class as a property inside that class. In the mainwondow class, we are creating an employee class object and initializing it with some values. Then we are creating an anotherclass object and initializing with the previously created employee object as well as one more property of anotherclass State” and then we are assigning this anotherclass object as dataconext. There are several ways to specify the binding source object. Using the DataContext property on a parent element is useful when you are binding multiple properties to the same source. However, sometimes it may be more appropriate to specify the binding source on individual binding declarations.

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;
namespace Bindingtoclasses
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            Employee P = new Employee("Hello World");
            P.State = "MD";
            AnotherClass c = new AnotherClass();
            c.EmployeeNameTest = P;
            c.AnotherField = "Another Value";
            this.DataContext = c;
        }
    }
    public class AnotherClass : INotifyPropertyChanged
    {
        private string anotherfield;
        private Employee emp;
        public string AnotherField
        {
            get { return anotherfield; }
            set
            {
                anotherfield = value;
                OnPropertyChanged("AnotherField");
            }
        }
        public Employee EmployeeNameTest
        {
            get { return emp; }
            set
            {
                emp = value;
                OnPropertyChanged("EmployeeNameTest");
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
        //// Create the OnPropertyChanged method to raise the event
        protected void OnPropertyChanged(string name)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(name));
            }
        }
        public override string ToString()
        {
            return string.Format("My ToString implementation of AnotherClass");
        }
    }
    // This class implements INotifyPropertyChanged to 
    // support one-way and two-way bindings
    // (such that the UI element updates when the source has been changed dynamically)
    public class Employee : INotifyPropertyChanged
    {
        private string name;
        private string state;
        // Declare the event
        public event PropertyChangedEventHandler PropertyChanged;
        public Employee()
        {
        }
        public Employee(string value)
        {
            this.name = value;
        }
        public string EmployeeName
        {
            get { return name; }
            set
            {
                name = value;
                // Call OnPropertyChanged whenever the property is updated
                OnPropertyChanged("EmployeeName");
            }
        }
        public string State
        {
            get { return state; }
            set
            {
                state = value;
                OnPropertyChanged("State");
            }
        }
        //// Create the OnPropertyChanged method to raise the event
        protected void OnPropertyChanged(string name)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(name));
            }
        }
    }
}

In the XAML: Even though we assigned the entire anotherclass object as datacontext, I am just assigning the EmployeeNameTest object in it as the datacontext for the grid using the code <Grid DataContext="{Binding Path=EmployeeNameTest}"> .

XML
<Window x:Class="Bindingtoclasses.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:src="clr-namespace:Bindingtoclasses"Title="MainWindow" Height="350" Width="525">
    <Grid DataContext="{Binding Path=EmployeeNameTest}">
        <Grid.Resources>
            <src:Employee x:Key="myDataSource" EmployeeName="Kishore1021"/>
        </Grid.Resources>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
        </Grid.RowDefinitions>
        <TextBox Name="TextBox1" Grid.Row="0" Text="{Binding Source=
    {StaticResource myDataSource}, Path=EmployeeName, 
    UpdateSourceTrigger=PropertyChanged}"/>
        <TextBox Name="TextBox2" Grid.Row="1" Text="{Binding Source= 
    {StaticResource myDataSource}, Path=EmployeeName}"></TextBox>
        <TextBox Name="TextBox3" Grid.Row="2" Text="{Binding Path=EmployeeName, 
    Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></TextBox>
        <TextBox Name="TextBox4" Grid.Row="3" Text="{Binding Path=EmployeeName}">
    </TextBox>
        <TextBlock Name="TextBlock1" Grid.Row="4" Text="{Binding Path=EmployeeName}"/>
        <TextBlock Name="TextBlock2" Grid.Row="5" Text="{Binding Path=AnotherField}"/>
    </Grid>
</Window>
  • Download the source code from here

Priority of Source VS DataContext

Code Snippet

XML
<Window x:Class="DataBinding_Source_Property.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="MainWindow" Height="350" Width="525" 
    xmlns:kishore="clr-namespace:DataBinding_Source_Property"> 
    <Window.Resources> 
        <kishore:Person x:Key="PersonXAMLDataSource" FullName="Kishore1021"/> 
        <kishore:Person x:Key="Person1" FullName="Person1Name"/> 
    </Window.Resources> 

    <Grid DataContext="{StaticResource Person1}"> 
        <Grid.RowDefinitions> 
            <RowDefinition Height="*"> </RowDefinition> 
            <RowDefinition Height="*"></RowDefinition> 
        </Grid.RowDefinitions> 

        <TextBox Grid.Row="0" Text="{Binding Source=
    {StaticResource PersonXAMLDataSource}, Path=FullName}"></TextBox> 
        <TextBox Grid.Row="1" Text="{Binding Path=FullName}"/> 
    </Grid> 
</Window>

The first TextBox inherits the DataContext from the parent Grid as well as has a Source set in the Binding object too. In this case, Source takes priority, causing the TextBox to bind to the Name property of the resource with key “PersonXAMLDataSource” – this displays “kishore1021”. The second inherits the DataContext from the parent Grid causing the TextBox to bind to the Name property of the resource with key “Person1”, causing it to display “Person1Name”. WPF will search up the element tree until it encounters a DataContext object if a Source or RelativeSource is not used. Once it finds a non-null DataContext, that object is used for binding. It is useful for binding several properties to the same object.

Most data bound applications tend to use DataContext much more heavily than Source. Use DataContext only when you need to bind more than one property to a particular source. When binding only one property to a source, always use Source. The reason for this is ease of debugging – We can see all the information about the Binding in one place, than search for the nearest DataContext to understand what is going on. Other than setting the DataContext property on an element directly, inheriting the DataContext value from an ancestor , and explicitly specifying the binding source by setting the Source property on the Binding, you can also use the ElementName property or the RelativeSource property to specify the binding source. The ElementName property is useful when you are binding to other elements in your application, such as when you are using a slider to adjust the width of a button. The RelativeSource property is useful when the binding is specified in a ControlTemplate or a Style.

"We must be silent before we can listen. We must listen before we can learn. We must learn before we can prepare. We must prepare before we can serve. We must serve before we can lead." - William Arthur Ward

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
CEO Astrani Technology Solutions
United States United States
Kishore Babu Gaddam is a Senior Technology Consultant, Technology Evangelist turned Technology Entrepreneur and a regular speaker at national conferences, regional code camps and local user groups with over 14 years of experience in software product development. His experience includes building & managing award-winning software development teams, managing customer relationships, marketing and launching new software products & services. Kishore launched his technology career almost 15 years ago with a Robotics software development startup and has served in multiple roles since including developer, innovation leader, consultant, technology executive and business owner.

A technology specialist in C++, C#, XAML and Azure, he successfully published two applications to Windows store http://bit.ly/WinStoreApp and http://bit.ly/FlagsApp.

Kishore is the author of the popular Microsoft Technologies blog at http://www.kishore1021.wordpress.com/ and his work on Portable Class Library project in Visual Studio 2012– .NET 4.5 was featured on Channel 9 at http://bit.ly/msdnchannel9. Kishore enjoys helping people understand technical concepts that may initially seem complex and perform lot of Research & Development on emerging technologies to help solve some of the toughest customer issues. Kishore spends a lot of time teaching and mentoring developers to learn new technologies and to be better developers. He is a speaker at various code camps around Washington DC area, mainly at Microsoft Technology Center for NOVA code camp (http://bit.ly/novacc12), CMAP Code Camp Fall 2012 (http://bit.ly/novacc12), etc. The majority of his software development experience has centered on Microsoft technologies including MFC, COM, COM+, WCF, WPF, winRT, HTML5, RestAPI and SQL Server. You can follow Kishore on Twitter at www.twitter.com/kishore1021. He can be reached on email at researcherkishore@outlook.com

Comments and Discussions

 
SuggestionNice blog, could be improved though Pin
sth_Weird1-Jul-15 1:09
sth_Weird1-Jul-15 1:09 
QuestionData Context Pin
Member 46367687-Mar-14 19:32
Member 46367687-Mar-14 19:32 
GeneralMy vote of 5 Pin
balaji_iitkgp2-Jul-13 19:14
balaji_iitkgp2-Jul-13 19:14 
GeneralMy vote of 1 PinPopular
Dean Oliver31-Jan-12 5:48
Dean Oliver31-Jan-12 5:48 
GeneralRe: My vote of 1 Pin
Saša Ćetković9-Apr-14 22:38
professionalSaša Ćetković9-Apr-14 22:38 
GeneralRe: My vote of 1 Pin
rami dagan19-May-15 2:42
rami dagan19-May-15 2:42 
GeneralRe: My vote of 1 Pin
DallyAU27-Sep-15 15:52
DallyAU27-Sep-15 15:52 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.