Many get confused over the two way databinding concept. This is usually done by implementing INotiyPropertyChanged interface.You can find many examples with INotiyPropertyChanged if you google for it. Here I am presenting a very basic example of WPF databinding to show its advantages.
Create a WPF Application called "TwoWayDataBinding". You have app.xaml and Window1.xaml. Add one class called Customer to the project. The code for the class is bellow.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TwoWayDataBind
{
class Customer
{
private string m_name;
public string Name
{
get { return m_name; }
set { m_name = value; }
}
private string m_State;
public string State
{
get { return m_State; }
set { m_State = value; }
}
}
}
We have two string properties called name and state in the customer class. We are going to use this class as the datasource for our WPF form.
Now look at the XAML code for the Window1.xaml file. The explanations will follow.
<Window x:Class="TwoWayDataBind.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:myapp="clr-namespace:TwoWayDataBind"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<myapp:Customer x:Key="Cust2" Name="Hansen" State="Arizona"/>
</Window.Resources>
<Grid x:Name="Grid1" DataContext="{StaticResource Cust2}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Grid.Row="0">Name:</TextBlock>
<TextBlock Grid.Column="0" Grid.Row="1">State:</TextBlock>
<TextBox x:Name="TextBox1" Grid.Column="1" Grid.Row="0" Text="{Binding Path=Name}"></TextBox>
<TextBox x:Name="TextBox2" Grid.Column="1" Grid.Row="1" Text="{Binding Path=State}"></TextBox>
<Button Grid.Column=" 1" Grid.Row="2" Name="button1" Click="OnClicked">Control To Context</Button>
</Grid>
</Window>
In the first line the class Name for the Window1 form is specified.
Next, there are two XML namespace declarations. The first declaration maps the overall Windows Presentation Foundation (WPF) namespace as the default:
The second declaration maps a separate Extensible Application Markup Language (XAML) namespace, mapping it (typically) to the x: prefix.
Coming on to the next part, you can map XML namespaces to assemblies using a series of tokens within an xmlns prefix declaration, similar to how the standard WPF and XAML namespaces are mapped to prefixes.We are mapping a xml namespace myapp with the TwoWayDataBind Assembly . This will be used in the next segment.
In the next section,we are declaring a resource dictionary. Microsoft defines these dictionaries as "Resource dictionaries that can be defined completely or partially in Extensible Application Markup Language (XAML) are typically created as a property element, and are typically on the root element for any individual page or for the application. Placing the resource dictionary at this level makes it easier to find from individual child elements in the page (or from any page, in the application case)". We are declaring a resource for window element, so that all child elements of the window can access it. You can also define resources for page,grid and other elements. We used the xml namespace myapp, that we mapped to our application assembly section. We are accesing the customer class of the TwoWayBindingAssmbly with myapp:Customer. We are defining a key for the resource, which will be used for accessing it from other elements in the form. We are also specifying values for the two customer properties.
Next we define the grid element for the WPF form. Look at the part DataContext="{StaticResource Cust2}. This is the important part for defining the databinding for our form. DataContext is a dependency property. It gets or sets the data context for an element when it participates in data binding. So are defining a datacontext for the Grid element here.We are defining the datacontext using the StaticResource. Static Resource provides a value for any XAML property attribute by looking up a reference to an already defined resource. That defined resource here is obviously Cust2, which is nothing but our customer class.
The Next 11 lines defines the form design xaml, as any wpf developer would find it easy to understand. Coming to the part of our interest :
<TextBox x:Name="TextBox1" Grid.Column="1" Grid.Row="0" Text="{Binding Path=Name}"></TextBox>
<TextBox x:Name="TextBox2" Grid.Column="1" Grid.Row="1" Text="{Binding Path=State}"></TextBox>
Here we are binding the text properties of the text boxes to the properties of the customer class. MSDN describes WPF databinding as "
To use WPF data
binding, you must always have a target and a source. The target of the
binding can be any accessible property or element that is derived from DependencyProperty—an example is a TextBox control's Text property. The source of the
binding can be any public property, including properties of other controls, common language runtime (CLR) objects, XAML elements, ADO.NET DataSets, XML Fragments, and so forth. To help you get the
binding right, WPF includes two special providers—the XmlDataProvider and the ObjectDataProvider."
The syntax we are using here is called attribute syntax. It condenses the data
binding code inside of the Text attribute of the TextBox. Basically, the
Binding tag gets pulled inside of the curly braces along with its attributes. "Path" is one of the Four components of Binding class. It gets or sets the path to the binding source property. So here we are setting the two properties of the customer class the the Binding source property of the textbox's text propety.
We have a button on the form and it has a click event method defined. Here is the code for the codebehind for the form.
Window1.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Data;
namespace TwoWayDataBind
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
private void OnClicked(object sender, RoutedEventArgs args)
{
Customer c1=Grid1.DataContext as Customer;
TextBox1.Text = c1.State;
}
}
}
Now if you run the project you will see.
So the textbox's are bound to the customer properties. We can see the values of the customer object in the texboxes.So this is one side of the databinding...the target object is getting update by the value of the data source. Now write something in the state textbox and click the button. What do you see? The Name textbox getting populated with the value of the State textBox.
If we look at the code for the button click:
Customer c1=Grid1.DataContext as Customer;
TextBox1.Text = c1.State;
We are not assigning the new value to the customer class or datacontext. As we type in the State textbox, the dataContext is getting updated. So when we assign the datacontext's State value to the Name textbox, we see it gets populated with the new value that is entered. Isn't it just fantastic?