[译]关于Data Binding,我不知道的10件事

http://dotnet.org.za/rudi/archive/2008/03/25/10-things-i-didn-t-know-about-wpf-data-binding.aspx

我的n层wpf项目中使用了大量的binding,现在我把我了解到的WPF中一些不太为人注意的地方贴出来。

1) Binding path "(TextBox.Text)" vs "Text"?

如果Path叫Text,那么WPF会使用反射机制,但是如果使用了类名作为修饰,则会避免反射带来的性能损失。Attached Property也是使用类名作修饰的。

 <StackPanel>
     <TextBox Name="txtShow"></TextBox>
     <TextBlock Text="{Binding ElementName=txtShow, Path=(TextBox.Text), UpdateSourceTrigger=PropertyChanged}"/>
 </StackPanel> 

2) WPF 不会抛出Binding异常

Binding中的异常(比如绑定不能解析等)只在是当作Trace信息显示,debug时可以在Output窗口中看到,不会在UI上抛出。
Beatriz Costa(或其他人)写过一篇很好的文章来解释这点。 
比如将上面的代码改为Path = a.Text,会有以下信息:
System.Windows.Data Error: 39 : BindingExpression path error: 'a' property not found on 'object' ''TextBox' (Name='txtShow')'.
BindingExpression:Path=a.Text; DataItem='TextBox' (Name='txtShow'); target element is 'TextBlock' (Name='');
target property is 'Text' (type 'String') 

3) 为什么使用 OneWayToSource binding?

要知道Binding中支持的目标都必须是Dependency Property。使用OneWayToSource就可以魔法免疫了。源不必是dependency property,另一方面,OneWayToSource可以改变绑定方向。

像Run就是一个不错的示例,其Text属性不是Denpendency Property。

参见这篇

<FlowDocumentScrollViewer>  
	<FlowDocument>  
		<Paragraph>This is a paragraph one.</Paragraph> 
		<Paragraph>
			<Run Name="runParagraphTwo" Text="{Binding ElementName=txtParagraph, Path=Text}"/>
		</Paragraph>
	</FlowDocument>
</FlowDocumentScrollViewer> 
这段代码想把一个叫txtParagraph的TextBox中的内容拷到Run中,但是像上面这么写是不行的,因为Run.Text不是Dependency Property。我们可以txtParagraph中利用OneWayToSource,源是txtParagraph.Text,而目标是Run,如下
<TextBlock Margin="5">Content for second paragraph: </TextBlock>
<TextBox Name="txtParagraph" Margin="5" MinLines="2" TextWrapping="Wrap" 
Text="{Binding ElementName=runParagraphTwo, Path=Text, Mode=OneWayToSource}"/>
当txtParagraph.Text的值变化后,会更新runParagraphTwo.Text
 
4) 默认的绑定模式?
并不是所有Dependency Property的默认绑定模式都是相同的。
如果绑定模式是TwoWay,但是CLR属性是readonly,则会异常,因为TwoWay要求源可读可写。要记得不能按照自己假定的绑定绑定写代码。
显式的写上绑定模式是个做法。同时要知道OneWay比TwoWay更轻量级,因为不用只绑一次,不用维护绑定关系,能用OneyWay就用OneWay。
 

5) RelativeSourceMode.PreviousData

这个小技巧在以下场景很有用:绑定到price的集合,需要显示前一个价格和当前价格的变化。
把当前集合中Item的值,和下面的Binding放在MultiBinding中,然后由继承自IMultiValueConverter的类算出两个价格的变化。
{Binding RelativeSource={RelativeSource PreviousData}}

参见这篇

展示了一个类似股市走向图的,叫做趋势图更好点吧,每个列上显示了对于前一个值的变化率。

image

 

<DataTemplate x:Key="RecordTemplate">
...........
...........
    <TextBlock Margin="3,0,0,3">
    <TextBlock.Text>
        <MultiBinding Converter="{StaticResource  RecordsDifferenceConverter}">
            <Binding/>
            <Binding RelativeSource="{RelativeSource PreviousData}"/>
        <MultiBinding>
    <TextBlock.Text>
    <TextBlock>
...........
...........
</DataTemplate>
 

6) RelativeSourceMode.FindAncestor

势图更好点我觉得这挺酷的。假设有一个ListBox,在DataTemplate中有一个TextBlock,如果不为它指定Foreground,那它会继承父Foreground属性。有趣的是,当选中它时,它的字段颜色会从黑变白。
现在假设DateTemplate中是一个用户自定义控件,其没有Foreground属性(举例来说,一个圆形,使用的是Fill而不是Foreground/Background)。如果把圆形回到DataTemplate中,而没设置Fill,显示时就是空白的。
在设置了Fill之后,在任何时候,包括选中它时,只会显示一种颜色,而不像TextBlock把前景色改成白色(这看起来更专业,和windows系统表现风格一致)。
所以如果让圆形继承Foreground是解决之道,如何让其在选中时变白?用下面的Binding设置圆的Fill:
{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}}, Path=Foreground}
现在,圆继承了父的Foreground,选中时会改变颜色。
 

7) 把自定义的对象绑到ListBox上,是怎么显示的?

当把自定义对象绑定到ListBox上,显示内容会是以下三个中的一个:
1. ListBox中DisplayMemberPath中指定的

2. DataTemplate中要表现的

3. 如果以上两个都未实现的话,调用自定义对象的ToString()方法

8){Binding Path=/}

绑定当前对象。要记得把IsSynchronizedWithCurrentItem设置为True。
[更新]在读Ian Griffiths 的blog时,对此有着详细的说明。

我的这篇blog中介绍Binding Path时也有介绍。

9)Binding类的一个构造方法接收Path作为参数

{Binding Name}与{Binding Path=Name}是一样的,前者更简洁。

10){Binding}

这看起来有点怪异,{Binding}的意思是说,源已经在逻辑树上定义了,向上回溯吧,比如把源设置到Windows的DataContext中。通过设置一个集合的DataContext,可以把把ListBox.ItemsSource设置为{Binding}。ListBox就会知道ItemsSource是逻辑树上最接近的那个DataContext。

这个还是要看我的这篇blog,还是Path那节。

转载于:https://www.cnblogs.com/iwteih/archive/2010/02/23/1672119.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值