ADODataSet
此示例演示了:
l 如何将DataSet中的一个表绑定了ListBox中;
l 指定明细的显示方式;
l 自定义转换。
要运行此示例,需要运行CopyData.cmd,此批处理复制BookData.mdb到ApplicationData目录。
首先初始化一个DataSet数据源,然后调用:
myListBox.DataContext = myDataSet;
表示为myListBox设置数据上下文为此DataSet,在XML中,描述为:
ItemSource=”{Binding Path=BookTable}”,表示绑定到子属性(在这里是DataSet的子表)BookTable。
<
ListBox
Name
="myListBox"
Height
="200"
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
ItemsSource
="{Binding Path=BookTable}"
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
ItemTemplate
="{StaticResource BookItemTemplate}"
/>
其中,
ItemTemplate ="{StaticResource BookItemTemplate}指定了明细的显示模板为静态资源BookItemTemplate,此静态资源的定义如下:
描述了明细使用3列显示,第一列绑定到Title属性,第二列绑定到ISBN属性,第三列绑定到NumPages属性。
<
DataTemplate
x:Key
="BookItemTemplate"
>
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
<
Grid
>
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
<
Grid
.ColumnDefinitions
>
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
<
ColumnDefinition
Width
="250"
/>
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
<
ColumnDefinition
Width
="100"
/>
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
<
ColumnDefinition
Width
="*"
/>
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
</
Grid.ColumnDefinitions
>
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
<
TextBlock
Text
="{Binding Path=Title}"
Grid.Column
="0"
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
FontWeight
="Bold"
/>
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
<
TextBlock
Text
="{Binding Path=ISBN}"
Grid.Column
="1"
/>
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
<
TextBlock
Grid.Column
="2"
Text
="{Binding Path=NumPages}"
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
Background
="{Binding Path=NumPages,
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
Converter={StaticResource MyConverter}}"
/>
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
</
Grid
>
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
</
DataTemplate
>
第三列的Background也绑定到NumPages属性中,但是你知道的,背景色怎么可以是数字类型呢?这里是指定了一个转换器,转化器是一个实现IValueConverter接口的对象。参考:IntColorConverter.cs。
BindConversionMarkup
此示例演示了:
l 转换器在转换时获取被转化的类型。
在红色的标签描述中:
前景色和文本都绑定到TheDate属性上,而且他们使用了相同的转换器,那么转换器如何在绑定时,正确的将文本返回给Text属性,而将颜色返回给Foreground属性呢?
<
TextBlock
Name
="myconvertedtext"
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
Foreground
="{Binding Path=TheDate,
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
Converter={StaticResource MyConverterReference}}"
>
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
<
TextBlock
.Text
>
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
<
Binding
Path
="TheDate"
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
Converter
="{StaticResource MyConverterReference}"
/>
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
</
TextBlock.Text
>
可以看出,Convert
通过检测被转换类型,将返回正确的数据,也就是说,绑定系统会正确的转递他希望的数据类型。
public
class
MyConverter : IValueConverter
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
{
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
public object Convert(object o, Type type,
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
object parameter, CultureInfo culture)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
DateTime date = (DateTime)o;
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
switch (type.Name)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
case "String":
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
return date.ToString("F", culture);
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
case "Brush":
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
return Brushes.Red;
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
default:
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
return o;
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
}
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
}
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
public object ConvertBack(object o, Type type,
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
object parameter, CultureInfo culture)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
return null;
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
}
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
}
BindDPtoDP
此示例演示了如何绑定到一个已有的控件上。
在此示例中,当我们下拉选择不同的颜色时,下面的正方形颜色会随之改变。下面是绑定代码:
在此代码中,可以设置绑定对象是一个当前的对象,使用ElementName指定,Path属性还是一样的。
<
Canvas
>
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
<
Canvas
.Background
>
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
<
Binding
ElementName
="myComboBox"
Path
="SelectedItem.Content"
/>
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
</
Canvas.Background
>
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
</
Canvas
>
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
当然,此示例也展示了绑定系统的自动转化功能,其数据源是字符串类型,目标被转化为一个颜色刷。
BindToMethod
这个示例功能是将标准温度转化为:摄氏度Celsius或者华氏度Fahrenheit,此转化是通过调用一个public string ConvertTemp(double degree, TempType temptype)方法获得最终的结果的。
此示例相对还是比较复杂的,首先声明一个方法类型的数据源:
<ObjectDataProvider ObjectType="{x:Type local:TemperatureScale}"
MethodName="ConvertTemp" x:Key="convertTemp">
<ObjectDataProvider.MethodParameters>
<system:Double>0</system:Double>
<local:TempType>Celsius</local:TempType>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
此XAML描述了使用TemperatureScale类实例的ConvertTemp方法作为数据源,当然,我们需要给一个默认的调用数据。
然后我们希望将文本框的内容绑定到方法的第一个参数上:
<TextBox.Text>
<Binding Source="{StaticResource convertTemp}" Path="MethodParameters[0]"
BindsDirectlyToSource="true" UpdateSourceTrigger="PropertyChanged"
Converter="{StaticResource doubleToString}">
<Binding.ValidationRules>
<local:InvalidCharacterRule/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
这里需要指定将字符串转化为double的转化器,而且还要有一个防止用户录入错误的数据的校验器。
第二步,我们需要将下拉框绑定到第二个参数:
<ComboBox Grid.Row="1" Grid.Column="2"
SelectedValue="{Binding Source={StaticResource convertTemp},
Path=MethodParameters[1], BindsDirectlyToSource=true}">
<local:TempType>Celsius</local:TempType>
<local:TempType>Fahrenheit</local:TempType>
</ComboBox>
和上面的一样,绑定到第二个参数上。
这里有个巧妙的地方,XAML直接将对象实例Celsius和Fahrenheit作为ComboBox的明细了,我们看见下拉框显示正确,而且可以不用转换器直接作为第二个参数。
最后就是绑定结果了:
<Label Content="{Binding Source={StaticResource convertTemp}}"
Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2"/>
HierarchicalDataTemplate
在这里例子中,我们将看见:
- 具有层次结构的数据绑定到树控件和菜单控件;
- 在延伸的代码中,你将看见这种绑定同样支持事件跟踪。
在此示例中,包含一个层次结构的数据对象:
在绑定到树控件和菜单时,是直接绑定的:
<TreeViewItem ItemsSource="{Binding Source={StaticResource MyList}}" Header="My Soccer Leagues" />
<MenuItem Header="My Soccer Leagues" ItemsSource="{Binding Source={StaticResource MyList}}" />
那么控件如何知道他的明细使用哪个集合属性呢?这里就靠HierarchicalDataTemplate了。
<HierarchicalDataTemplate DataType = "{x:Type src:League}"
ItemsSource = "{Binding Path=Divisions}">
<TextBlock Text="{Binding Path=Name}"/>
</HierarchicalDataTemplate>
上面的XAML作为资源定义,描述为类型League的明细使用Divisions属性。
最后我对这个示例程序进行了改造,首先修改数据类的所有List类型改为ObservableCollection,以便集合实现更改通知。然后我添加了一个菜单:AddTeam,单击此菜单时,我向数据源添加了一个Team对象,我发现绑定系统都自动检测到这个改变了。
因此,我们可以利用此特性,定义一个描述菜单的实体结构,然后绑定到菜单上,这样,实际的代码将操控与特定菜单实现无关的实体,从而达到隔离的目的。
BindValidation
此示例演示了:
- 如何使用错误模板;
- 使用样式显示错误信息;
- 如何在校验发生异常时执行回调;
![](https://i-blog.csdnimg.cn/blog_migrate/9816dc9781c05a4344f7c82ad57bec8c.jpeg)
首先,你可以看见XAML中使用自定义的错误模板,指定错误模板的方式是:
<
TextBox
Name
="textBox1"
Validation.ErrorTemplate
="{StaticResource validationTemplate}"
Style
="{StaticResource textBoxInError}"
>
<
TextBox
.Text
>
此错误模板我简单改造了一下,变得好看点:
<
ControlTemplate
x:Key
="validationTemplate"
>
<
DockPanel
>
<
Image
Source
="Error.jpg"
Width
="16"
Height
="16"
/>
<
AdornedElementPlaceholder
/>
</
DockPanel
>
</
ControlTemplate
>
注意这个模板是ControlTemplate(为什么是控件模板我也不知道,照葫芦画瓢),然后定义了一个布局,左边一个图像,右边一个AdornedElementPlaceholder占位符。
(我在实验时,图像如果没有加入Width和Height,在显示时图片将变得很大)。
当然,你也可以使用样式绑定到异常上来显示错误,例如:
<
Style
x:Key
="textBoxInError"
TargetType
="{x:Type TextBox}"
>
<
Style
.Triggers
>
<
Trigger
Property
="Validation.HasError"
Value
="true"
>
<
Setter
Property
="ToolTip"
Value
="{Binding RelativeSource={x:Static RelativeSource.Self},
Path=(Validation.Errors)[0].ErrorContent}"
/>
</
Trigger
>
</
Style.Triggers
>
</
Style
>
当然,例子中还显示了,如果校验时发生异常(注意:是异常不是不正确的数据),将发生回调:
BindingExpression myBindingExpression
=
textBox3.GetBindingExpression(TextBox.TextProperty);
Binding myBinding
=
myBindingExpression.ParentBinding;
myBinding.UpdateSourceExceptionFilter
=
new
UpdateSourceExceptionFilterCallback(ReturnExceptionHandler);
myBindingExpression.UpdateSource();