上一章介绍了依赖属性,本章开始介绍WPF中最重要的部分-绑定。
数据绑定实际上关联数据源和目标的一种方式,其目标一般是应用程序的用户界面。数据源则可能是一个集合对象,一个XML文件,一个Web服务,一个数据表,一个自定义对象,甚至一个WPF元素,如Button。当数据发送改变时,用户界面会自动反映该变化。
WFP中的绑定
在WPF中,有两种属性,属性和依赖属性。WPF也支持命令行绑定,让我们讨论下他们具体是怎么执行的。绑定分为数据绑定和类型绑定。
数据绑定
ObjectDataProvider和XMLDataprovider
等对象加强XAML中的对象绑定能力,WPF中数据绑定是非常灵活的。
1 <TextBox x:Name="txtName" />
2 <TextBlock Text="{Binding ElementName=txtName, Path=Text.Length}" />
TextBlock和TextTextBox txtName进行绑定,在程序运行时无论你什么时候改变了TextBox,TextBlock都会反映string的长度。标记扩展实际上是一个属性类,这里我们指定了ElementName和Path,ElementName决定可对象属性的归属,Path决定了对象显示的内容。
ObjectDataProvider装载数据是非常简单的。ObjectDataProvider能够作为静态资源调用,看下面的代码。
1 <StackPanel Orientation="Vertical">
2 <StackPanel.Resources>
3 <ObjectDataProvider ObjectType="{x:Type m:StringData}"
4 x:Key="objStrings" MethodName="GetStrings"/>
5 </StackPanel.Resources>
6 <ListBox Name="lstStrings" Width="200" Height="300"
7 ItemsSource="{Binding Source={StaticResource objStrings}}" />
ObjectType是一个内置类结构,使用StaticResource调用对象,声明一个类。
1 public class StringData
2 {
3 ObservableCollection<String> lst= new ObservableCollection<String>();
4
5 public StringData()
6 {
7 lst.Add("Abhishek");
8 lst.Add("Abhijit");
9 lst.Add("Kunal");
10 lst.Add("Sheo");
11 }
12 public ObservableCollection<String> GetStrings()
13 {
14 return lst;
15 }
16 }
ObvervableCollection,ObvervableCollection能够在新对象插入时发出自动通知,使得ListBox进行更新,不需要手动进行。
WPF绑定在数据改变时需要进行通知,INotifyPropertyChanged和INotifyCollectionChanged需要在随着绑定的数据发送改变时更新UI控件,所以如果你想要在绑定数据发生改变的时候同时改变UI,实现INotifycollectionChanged是基本要求,对于像ItemsSource一样的集合,执行INotifyCollectionChanged。ObservableCollection本身包含了INotifyCollectionChanged,因此不管什么时候,当新元素插入或者旧元素删除的时候都会自动更新ListBox。
XML绑定
Binding类中定义的XPath从XMLDataProvider绑定数据。
<TextBlock Text="{Binding XPath=@description}"/>
<TextBlock Text="{Binding XPath=text()}"/>
XYZ节点,内部的文本可以使用text()属性取出,@标志用于属性,使用XPath,可以轻松的转载XML。
数据文本的重要性
DataContext),DataContext是一种依赖属性当你为网格定义了一个DataContext属性,然后网格所有元素都将得到相同的DataContext。
<Grid DataContext="{StaticResource dtItem}">
<TextBox Text="{Binding MyProperty}" />
</Grid>
DataContext,网格内的TextBox能够引用属性MyProperty作为dtItem对象。
绑定成员
绑定实际上是一种标记扩展,让我们讨论下绑定的成员:
1. Source:DataSource的源属性。默认引用了控件的DataContext属性。
2.ElementName:ElementName是在XAML中定义的需要引用的对象名字。假如path没有指定,使用ToString从源对象中获取数据。
3.Path:定义了实际属性的路径,目的是得到String Data。假如对象不是一个String,它将调用ToString得到数据。
4.Mode:定义了数据传送的模式。从图的角度来说存在3中状态。
OneWay
正如图A所说,Source影响着Target,但是Target却影响不到Source。
OneWayToSource
也正如图B中所表述的一样,Target影响Source,而Source却影响不到Target。
TwoWay
这个也就相当于无向图的边,Source与Target相互影响。
OneTime
在OneWay的基础上延伸了一个OneTime,仅绑定一次。如果大家属性Jquery中的one函数我想就可以不用表述了。
5.UpdateSourceTrigger:当源对象发生改变时触发,可以是:
PropertyChanged:默认选项,不管控件中发生什么改变,都会反映到绑定的对象中。
LostFocus:属性失去焦点是触发。
Explicit:源更新时,你需要显式的设置,使用UpdateSource和BindingExpression更新控件。
6.Converter:当源更新时,提供一个可以设置调用对象的接口。
7:ConverterParameter:Converter参数设置。
8:FallbackValue:当绑定没有返回值的时候定义的返回值,默认为空
9:StringFormat:一个格式化的字符串表明数据传输遵循的格式。
10:ValidatesOnDataErrors: DataErrors得到验证。
后台代码绑定
Binding myBinding = new Binding("DataObject");
myBinding.Source = myDataObject;
myTextBlock.SetBinding(TextBlock.TextProperty, myBinding);
多重绑定
<TextBlock DockPanel.Dock="Top" >
<TextBlock.Text>
<MultiBinding Converter="{StaticResource mbindingconv}">
<Binding ElementName="lst" Path="Items.Count" />
<Binding ElementName="txtName" Path="Text" />
<Binding ElementName="txtAge" Path="Text" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
TextBox的值依赖与3个元素:ListBox count,txtName和txtAge,我使用Converter来确保我们能有在IMultiValueConverter块中找到所有的元素,然后一个个加载它们。IMultiValueConverter和IValueConverter是类似的,能够设置和返回与Text绑定的对象。
public class MyMultiBindingConverter : IMultiValueConverter
{
#region IMultiValueConverter Members
public object Convert(object[] values, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
string returnval = "Total no of Data {0}, NewData : ";
if (values.Count() <= 0) return string.Empty;
returnval = string.Format(returnval, values[0]);
for (int i = 1; i < values.Count(); i++)
returnval += "- " + values[i];
return returnval;
}
public object[] ConvertBack(object value, Type[]
targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
简便起见,我合并可多个数组。