- Usually you should define a decorator class for UI, for example,
// if you want to update UI automatically when property "Title" is change, we need add code in green.
public class DataBindingDecorator : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
// NotifyPropertyChanged will raise the PropertyChanged event passing the
// source property that is being updated.
public void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
// define some properties
private string title;
public string Title {
get {return title;}
set
{
title = value;
NotifyPropertyChanged("Title");
}
}
// MyWindow.xaml.cs
public class MyWindow: Window
{
// for example, use listbox
// ObservableCollection represents a dynamic data collection that provides notifications when items
// get added, removed, or when the whole list is refreshed. The UI will be updated automatically when items are changed.
// If you use IList instead of ObservableCollection, then when items get added, removed, you need update UI manually, for example, you need set ItemsSource constantly.
public ObservableCollection<DataBindingDecorator> items= new ObservableCollection<DataBindingDecorator>();
public ObservableCollection<DataBindingDecorator> Items
{
get
{
return items;
}
set
{
items= value;
}
}
// Way 1: you can binding items/Items to listbox control in this class using code, for example
ListBox.ItemsSource = items;
}
// MyWindow.xaml
// Way 2: you can binding Items to listbox control in xaml. (you can only bind property in xaml, but not member variable) for example
<ItemsControl Name="ItemsList" ItemsSource="{Binding ElementName=MyWindow, Path=Items}"
// You can binding control attribute in DataTemplate (define each listbox item) to properties in class DataBindingDecorator
- ObservableCollection<T> vs INotifyPropertyChanged
- To fully support transferring data values from binding source objects (ObservableCollection<T>) to binding targets, each object (T type) in your collection that supports bindable properties must implement an appropriate property changed notification mechanism such as the INotifyPropertyChanged interface.
- ObservableCollection<T> does implement INotifyPropertyChanged, however it only raises PropertyChanged events for changes in its own properties, not for the properties of the items which it contains. Therefore, you will find that PropertyChanged events occur when you add a new item to indicate that the Count property of the collection has changed.
- ObservableCollection<T> only ensure that UI updated automatically when elements number is changed (add/remove)in ObservableCollection<T>; if you want ensure that UI updated automatically when the properties in T is change, T must implement the interface INotifyPropertyChanged.
- To fully support transferring data values from binding source objects (ObservableCollection<T>) to binding targets, each object (T type) in your collection that supports bindable properties must implement an appropriate property changed notification mechanism such as the INotifyPropertyChanged interface.
- You can use DataContex, ElementName to do data binding. For example,
// MyWindow.xaml
<Window x:Class="MyWindow"
Name="myWindow">
<Grid Name="myGrid">
<TextBox Height="23" HorizontalAlignment="Left" Margin="25,37,8,251" Text="{Binding DataContextBinding}"/> // show "data context binding"
<TextBox Height="23" HorizontalAlignment="Left" Margin="25,37,8,251" Text="{Binding Path=DataContextBinding}"/> // show "data context binding"
<TextBox Height="23" HorizontalAlignment="Left" Margin="25,37,8,251" Text="{Binding ElementName=myWindow, Path=ElementNameBinding}"/> // show "element name binding"
</Grid>
</Window>
// MyWindow.xaml.cs
public class BindingData
{
private string m_value = string.Empty;
public BindingData() { }
public string DataContextBinding
{
get
{
return "data context binding";
}
set
{
m_value = value;
}
}
}
public class MyWindow: Window
{
private string m_value = string.Empty;
public string ElementNameBinding
{
get
{
return "element name binding";
}
set
{
m_value = value;
}
}
private BindingData myData = new BindingData();
public MainWindow()
{
myGrid.DataContext = myData;
}
}
- How to specify the binding source: DataContext, Source, RelativeSource and ElementName
- DataContext: Use DataContext only when you need to bind more than one property to a particular source. Establish a scope in which several properties inherit the same data context.
- Source: When binding only one property to a source, always use Source. You use this property to set the source to an instance of an object. If you do not need the functionality of establishing a scope in which several properties inherit the same data context, you can use the Source property instead of the DataContext property.
- RelativeSource: This is useful when you want to specify the source relative to where your binding target is. Some common scenarios where you may use this property is when you want to bind one property of your element to another property of the same element or if you are defining a binding in a style or a template.
- ElementName: You specify a string that represents the element you want to bind to. This is useful when you want to bind to the property of another element on your application. For example, if you want to use a Slider to control the height of another control in your application, or if you want to bind the Content of your control to the SelectedValueproperty of your ListBox control.
- However, only one of the three properties, ElementName, Source, andRelativeSource, should be set for each binding, or a conflict can occur.