Canvas.Left="{BindingPath=Value,ElementName=slider}"
Name="FunnyFace"Height="210"Width="230">
在后台代码中,必须创建一个新的Binding对象,设置Path和Source属性。
Source属性必须设置为源对象,这里是WPF对象slider。
Path属性设置为一个PropertyPath实例,它用源对象的Value属性名初始化。
对于目标,可以调用SetBinding()方法来定义绑定。
这里,目标是名为FunnyFace的Canvas对象。
SetBinding()方法需要两个参数,第一个参数是一个依赖属性,第二个参数是绑定对象。
Canvas.Left属性应是绑定的,这样DependencyProperty类型的依赖属性才能用Canvas.LeftProperty字段访问:
Bindingbinding=newBinding();
binding.Path=newPropertyPath("Value");
binding.Source=slider;
FunnyFace.SetBinding(Canvas.LeftProperty,binding);
使用Binding类,可以配置许多绑定选项,如表35-2所示。
表 35-2
Binding类的成员
说明
Source
使用Source属性,可以定义数据绑定的源对象
RelativeSource
使用RelativeSource属性,可以指定与目标对象相关的源对象。
当错误来源于同一个控件时,它可用于显示错误消息
ElementName
如果源对象是一个WPF元素,就可以用ElementName属性指定源对象
Path
使用Path属性,可以指定到源对象的路径。
它可以是源对象的属性,也支持子元素的索引符和属性
XPath
使用XML数据源时,可以定义一个XPath查询表达式,来获得要绑定的数据
Mode
模式定义了绑定的方向。
Mode属性是BindingMode类型。
BindingMode是一个枚举,其值如下:
Default、OneTime、OneWay、TwoWay、OneWayToSource。
默认模式依赖于目标:
对于文本框,双向绑定是默认值;对于只读的标签,默认为单向;OneTime表示数据仅从源中加载一次。
OneWay还可以将对源对象的修改更新到目标对象中。
TwoWay绑定表示,对WPF元素的修改可以写回源对象。
OneWayToSource表示,从不读取数据,但总是从目标对象写入源对象
Converter
使用Converter属性,可以指定一个转换器类,来回转换UI的数据。
转换器类必须实现接口IValueConverter,它定义了方法Convert()和ConvertBack()。
使用ConverterParameter属性可以给转换方法传送参数。
转换器对文化很敏感,文化可以用ConverterCultrue属性设置
FallbackValue
使用FallbackValue属性,可以定义一个在绑定没有返回值时使用的默认值
ValidationRules
使用ValidationRules属性,可以定义一个ValidationRule对象集合,在用WPF目标元素更新源对象之前检查该集合。
ExceptionValidationRule类派生自ValidationRule类,负责检查异常
35.1.3 简单对象的绑定
要绑定CLR对象,只需使用.NET类定义属性,如下面的例子就使用类Book定义了属性Title、Publisher、Isbn和Authors:
publicclassBook
{
publicBook(stringtitle,stringpublisher,stringisbn,
paramsstring[]authors)
{
this.title=title;
this.publisher=publisher;
this.isbn=isbn;
foreach(stringauthorinauthors)
{
this.authors.Add(author);
}
}
publicBook()
:
this("unknown","unknown","unknown")
{
}
publicstringTitle{get;set;}
publicstringPublisher{get;set;}
publicstringIsbn{get;set;}
publicoverridestringToString()
{
returntitle;
}
privatereadonlyListauthors=newList();
publicstring[]Authors
{
get{returnauthors.ToArray();}
}
}
在用户界面上,定义了几个标签和文本框控件,以显示图书信息。
使用Binding标记扩展,将文本框控件绑定到Book类的属性上。
在Binding标记扩展中,仅定义了Path属性,将它绑定到Book类的属性上。
不需要定义源对象,因为源对象是通过指定DataContext来定义的,如下面的后台代码所示。
对于TextBox元素,模式定义为默认值,即双向绑定:
Class="ObjectBindingSample.Window1"
xmlns="
xmlns:
x="
Title="ObjectBindingSample"Height="300"Width="340">
Title:
Text="{BindingTitle}"/>
Publisher:
Text="{BindingPublisher}"/>
ISBN:
Text="{BindingIsbn}"/>
Name="bookButton">OpenDialog
在后台代码中定义了一个新的Book对象,并将其赋予Grid控件的DataContext属性。
DataContext是一个依赖属性,用基类FrameworkElement定义。
指定Grid控件的DataContext属性表示,Grid控件中的每个元素都默认绑定到同一个数据环境上。
publicpartialclassWindow1:
System.Windows.Window
{
privateBookbook1=newBook();
publicWindow1()
{
InitializeComponent();
book1.Title="ProfessionalC#2005with.NETC#3.0";
book1.Publisher="WroxPress";
book1.Isbn="978-0764575341";
bookGrid.DataContext=book1;
}
}
启动应用程序,就会看到图35-4所示的绑定数据。
为了实现双向绑定(对WPF元素的修改反映到CLR对象上),定义了方法OnOpenBookDialog()。
这个方法指定为bookButton的Click事件,如下面的XAML代码所示。
在执行时,会弹出一个消息框,显示book1对象的当前标题和ISBN号。
图35-5显示了在运行过程中修改了一个输入后消息框的结果。
voidOnOpenBookDialog(objectsender,RoutedEventArgse)
{
stringmessage=book1.Title;
stringcaption=book1.Isbn;
MessageBox.Show(message,caption);
}
图 35-4
图 35-5
35.1.4 对象数据提供程序
除了在后台代码中定义对象之外,还可以用XAML定义对象实例。
为此,必须引用在XML根元素的命名空间中声明的命名空间。
XML属性xmlns:
src="clr-namespace:
Wrox.ProCsharp.WPF"将.NET命名空间Wrox.ProCSharp.WPF赋予XML命名空间别名src。
现在,在Window资源中用Book元素定义Book类的一个对象。
给XML属性Title和Publisher赋值,就设置了类Book的属性值。
x:
Key="theBook"定义了资源的标识符,以便引用book对象。
在TextBox元素中,Source是用Binding标记扩展定义的,以引用theBook资源。
提示:
可以合并标记扩展。
在下面的例子中,引用图书资源的StaticResource标记扩展包含在Binding标记扩展中。
Class="ObjectBindingSample.Window1"
xmlns="
xmlns:
x="
xmlns:
src="clr-namespace:
Wrox.ProCSharp.WPF"
Title="ObjectBindingSample"Height="300"Width="340">
Bookx:
Key="theBook"Title="ProfessionalC#2008"
Publisher="WroxPress"/>
--...-->
Text="{BindingSource={StaticResourcetheBook},Path=Title}"/>
--...-->
提示:
如果要引用的.NET命名空间在另一个程序集中,就必须把该程序集添加到XML声明中。
xmlns:
system="clr-namespace:
System;assembly=mscorlib".
除了直接在XAML代码中定义对象实例外,还可以定义一个对象数据提供程序,来引用类,调用方法。
为了使用ObjectDataProvider,最好创建一个返回要显示的对象的工厂类,如下面的BookFactory类所示:
publicclassBookFactory
{
privateListbooks=newList();
publicBookFactory()
{
books.Add(newBook("ProfessionalC#2008",
"WroxPress","978-0470191378"));
}
publicBookGetTheBook()
{
returnbooks[0];
}
}
ObjectDataProvider元素可以在资源段中定义。
XML属性ObjectType定义了类的名称,MethodName指定了要调用以获得book对象的方法名:
BookFactory"MethodName="GetTheBook"
x:
Key="theBook">
可以用ObjectDataProvider类指定的属性如表35-3所示。
表 35-3
ObjectDataProvider
说明
ObjectType
ObjectType属性定义了要创建的实例类型
ConstrutorParameters
使用ConstructorParameters集合可以在类中添加创建实例的参数
MethodName
MethodName属性定义了由对象数据提供程序调用的方法名
MethodParameters
使用MethodParameters属性可以给通过MethodName属性定义的方法指定参数
ObjectInstance
使用ObjectInstance属性,可以获取和设置由ObjectDataProvider类使用的对象。
例如,可以用编程方式指定已有的对象,以便用ObjectDataProvider实例化一个对象,而不是定义ObjectType
Data
使用Data属性,可以访问用于数据绑定的底层对象。
如果定义了MethodName,则使用Data属性,可以访问从指定的方法返回的对象
35.1.5 列表绑定
绑定到列表上比绑定到简单对象上更灵活,但这两种绑定非常类似。
可以在后台代码中将完整的列表赋予DataContext,也可以使用ObjectDataProvider访问一个对象工厂,以返回一个列表。
对支持绑定到列表上的元素(如列表框),会绑定整个列表。
对于只支持绑定一个对象的元素(如文本框),就绑定当前的数据项。
使用BookFactory类,会返回一个Book对象列表:
publicclassBookFactory
{
privateListbooks=newList();
publicBookFactory()
{
books.Add(newBook("ProfessionalC#2008","WroxPress",
"978-0470191378","ChristianNagel","BillEvjen",
"JayGlynn","KarliWatson","MorganSkinner"));
books.Add(newBook("ProfessionalC#2005with.NET3.0",
"WroxPress","978-0-470-12472-7","ChristianNagel",
"BillEvjen","JayGlynn","KarliWatson","MorganSkinner"));
books.Add(newBook("ProfessionalC#2005",
"WroxPress","978-0-7645-7534-1","ChristianNagel",
"BillEvjen","JayGlynn","KarliWatson","MorganSkinner",
"AllenJones"));
books.Add(newBook("BeginningVisualC#",
"WroxPress","978-0-7