I. Binding to Object
1. Binding data using ObjectDataProvider
AC:Let’s say there is a CLR based data bound object that you are trying to implement. For example a collection of Tool objects, e.g.
- An Object called Tool that contains a bunch of properties that we want to bind (in this case it just contains a description)
- A Collection of Tool objects( ToolsCollection ); for example to populate a list box etc
- A Factory to get the reference of ToolsCollection objects which have collection<Tools>
using
System;
using
System.Collections.Generic;
using
System.Collections.ObjectModel;
using
System.ComponentModel;
using
System.Linq;
using
System.Text;
using
System.Threading.Tasks;
namespace
CLRDataBinding
{
public
class
Tool : INotifyPropertyChanged
{
private
string
_description =
""
;
public
string
Description
{
get
{
return
_description;
}
set
{
if
(_description !=
value)
{
_description
=
value;
NotifyPropertyChanged(
"
Description
"
);
}
}
}
public
Tool(
string
description)
{
_description
=
description;
}
public
event
PropertyChangedEventHandler PropertyChanged;
protected
void
NotifyPropertyChanged(
string
propName)
{
if
(PropertyChanged !=
null
)
{
PropertyChanged(
this
,
new
PropertyChangedEventArgs(propName));
}
}
}
}
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Text;
using
System.Threading.Tasks;
using
System.Collections.ObjectModel;
namespace
CLRDataBinding
{
public
class
ToolsCollection : ObservableCollection<Tool>
{
public
ToolsCollection()
{
CreateToolsData();
}
private
void
CreateToolsData()
{
for
(
int
loop =
0
; loop <
1000
; loop++
)
{
this
.Add(
new
Tool(
"
Tool
"
+
loop.ToString()));
}
}
}
}
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Text;
using
System.Threading.Tasks;
namespace
CLRDataBinding
{
public
class
Factory
{
public
ToolsCollection MyToolsCollection
{
get
{
return
new
ToolsCollection(); }
}
}
}
<
Window
x:Class
="CLRDataBinding.MainWindow"
xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:clr
="clr-namespace:CLRDataBinding"
Title
="MainWindow"
Width
="525"
Height
="350"
>
<
Window.Resources
>
<
ObjectDataProvider
x:Key
="FactoryDP"
ObjectType
="
{x:Type clr:Factory}
"
/>
<
DataTemplate
x:Key
="ToolItemTemplate"
>
<
StackPanel
>
<
TextBlock
Text
="
{Binding Description}
"
/>
</
StackPanel
>
</
DataTemplate
>
</
Window.Resources
>
<
Grid
>
<
ListBox
ItemTemplate
="
{StaticResource ToolItemTemplate}
"
ItemsSource
="
{Binding Path=MyToolsCollection, Source={StaticResource FactoryDP}}
"
/>
</
Grid
>
</
Window
>
之前一篇文章 对象数据绑定 里提到三个例子,第一个例子用了ObjectDataProvider没有用DataContext,第二个例子用了DataContext没有用 ObjectDataProvider,第三个例子既用了ObjectDataProvider也用了DataContext,但没有提到它们的区别,正 好在Beatriz Costa的blog上看到一篇好文章解释了为 什么需要 ObjectDataProvider 的问题。
ObjectDataProvider能实现四个特殊功能:
1. 传递参数到构造函数中
使用下面的XAML语句定义一个ObjectDataProvider,它会自动调用MySource类的默认构造函数初始化类
<ObjectDataProvider ObjectType="{x:Type local:MySource}" x:Key="odp1"/>
如果MySource类的构造函数允许传入参数的话,就可以这样定义ObjectDataProvider:
<ObjectDataProvider ObjectType="{x:Type local:MySource}" x:Key="odp1">
<ObjectDataProvider.ConstructorParameters>
<system:String>Jupiter</system:String>
</ObjectDataProvider.ConstructorParameters>
</ObjectDataProvider>
2. 绑定到方法
ObjectDataProvider 除了 ObjectType的属性外还有MethodName的属性,MethodName属性将ObjectDataProvider绑定到方法,相当于是对数据源的包装,另外也可以定义方法的传入参数:
<ObjectDataProvider ObjectInstance="{StaticResource odp1}" MethodName="WeightOnPlanet" x:Key="odp2">
<ObjectDataProvider.MethodParameters>
<system:Double>95</system:Double>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
3. 替换数据对象
和使用自己在resource中定义对象不同,ObjectDataProvider可以使里很简单的更换绑定的数据对象,只需要更换一下绑定的数据对象的名字。而使用自己在resource中定义对象,即使定义了相同的x:Key也不能达到自动更新的目的。
另,这里使用DataContext也能达到与ObjectDataProvider同样的效果。
4. 建立异步的数据对象
ObjectDataProvider有IsAsynchronous 可以将数据对象定义为异步的。
默认情况下ObjectDataProvider是同步的,XmlDataProvider是异步。
2. Binding DataContext in Window.DataContext (ObjectDataProvider not needed)
AuctionItem.cs: define
Class
AuctionItem
:
INotifyPropertyChanged
MyApp.xaml.cs: define
Class
AuctionItems
:
ObservableCollection<AuctionItem>
Window1.xaml.cs: use [CollectionViewSource cv = root.DataContext as CollectionViewSource;] to action in button event handler
Binding Process:
1)Define DataContext in Window1.xaml:
<
Window.DataContext
>
<
CollectionViewSource
>
<
CollectionViewSource.Source
>
<
local:AuctionItems
/>
</
CollectionViewSource.Source
>
</
CollectionViewSource
>
</
Window.DataContext
>
2) Binding Listbox:
<
ListBox
ItemsSource
="
{Binding Path=.}
"
IsSynchronizedWithCurrentItem
="True"
>
3) Binding label: (the current item in listbox)
<
Label
Content
="
{Binding Path=/}
"
>
4) DataTemplate
<
DataTemplate
DataType
="
{x:Type local:AuctionItem}
"
>
...
<
Image
>
<
Image.Source
>
<
Binding
Path
="Image"
/>
</
Image.Source
>
</
Image
>
...
More: this sample also shows how to use Converter and MultiBinding
3. Binding DataContext in controls to Global ObjectDataProvider
sample:
MyApp.xaml:
<
Application.Resources
>
...
<
ObjectDataProvider
x:Key
="Employees"
ObjectType
="
{x:Type local:MSEmployeeCollection}
"
/>
</
Application.Resources
>
Window1.xaml:
<
StackPanel
Margin
="10"
DataContext
="
{StaticResource Employees}
"
>
...
<
Button
Content
="
{Binding Path=[0]}
"
/>
<
ComboBox
ItemsSource
="
{Binding}
"
SelectedIndex
="0"
/>
</
StackPanel
>
1) DataContext another format : binding to StackPanel
2) Button bind to single item [0]
3) ComblBox bind to multi items, so no Path
II. Binding to XML
1. Use Source include .xml file to XmlDataProvider
<?
xml version='1.0' encoding='utf-8'
?>
<
StackPanel
xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
Margin
="10"
>
<
StackPanel.Resources
>
<
XmlDataProvider
x:Key
="Blog"
Source
="http://home.wangjianshuo.com/index.xml"
/>
<
DataTemplate
x:Key
="TitleTemplate"
>
<
TextBlock
Text
="
{Binding XPath=title}
"
/>
</
DataTemplate
>
</
StackPanel.Resources
>
<
Label
Content
="
{Binding Source={StaticResource Blog}, XPath=/rss/channel/title}
"
FontSize
="24"
FontWeight
="Bold"
/>
<
Label
Content
="
{Binding Source={StaticResource Blog}, XPath=/rss/channel/description}
"
FontSize
="18"
/>
<
DockPanel
DataContext
="
{Binding Source={StaticResource Blog}, XPath=/rss/channel/item}
"
>
<
ListBox
DockPanel.Dock
="Left"
ItemsSource
="
{Binding}
"
ItemTemplate
="
{StaticResource TitleTemplate}
"
IsSynchronizedWithCurrentItem
="True"
/>
<
TextBox
Name
="Contents"
Text
="
{Binding XPath=description}
"
TextWrapping
="Wrap"
Width
="Auto"
/>
</
DockPanel
>
</
StackPanel
>
2. Use x:XData define the xml structure inside current XmlDataProvider
<
StackPanel
xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
>
<
StackPanel.Resources
>
<
XmlDataProvider
x:Key
="FavoriteColors"
>
<
x:XData
>
<
Colors
xmlns
=""
>
<
Color
>
Blue
</
Color
>
<
Color
>
Black
</
Color
>
<
Color
>
Green
</
Color
>
<
Color
>
Red
</
Color
>
</
Colors
>
</
x:XData
>
</
XmlDataProvider
>
</
StackPanel.Resources
>
<
TextBlock
HorizontalAlignment
="Center"
FontWeight
="Bold"
>
XML Example
</
TextBlock
>
<
ListBox
Width
="200"
Height
="300"
ItemsSource
="
{Binding Source={StaticResource FavoriteColors},
XPath=/Colors/Color}
"
>
</
ListBox
>
</
StackPanel
>
III. Binding to Control
1:
<
Window
xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
>
<
Canvas
>
<
TextBox
Name
="theTextBox"
Text
="Hello"
/>
<
TextBlock
Canvas.Top
="25"
>
<
TextBlock.Text
>
<
Binding
ElementName
="theTextBox"
Path
="Text"
/>
</
TextBlock.Text
>
</
TextBlock
>
</
Canvas
>
</
Window
>
2:
<
Window
xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
>
<
Canvas
>
<
TextBox
Name
="theTextBox"
Text
="Hello"
/>
<
TextBlock
Canvas.Top
="25"
Text
="
{Binding ElementName=theTextBox, Path=Text}
"
/>
</
Canvas
>
</
Window
>
IX. Binding to ADO.NET
Similar to binding to object, create a dataset and return ds to DataContext.

