简单的说 数据绑定 是一个关系,该关系告诉WPF 从源对像提取一些信息,并用这些信息设置目标对像的属性。
在目标对像中,被设置绑定的属性必须是 依赖项属性,通常在WPF 元素中。
注意:
尽管从元素到元素的绑定是最简单的方,但是在真正的项目开发中,大量的数据绑定是将元素x绑定到数据对像。从而可以显示 从 数据库或者文件 中提取的数据。
从元素到元素的绑定通常应用于元素的交互方式自动化,用户自定义控件。
使用 xaml 标记拓展(也就是用{}语法)。
<TextBox x:Name="sourceTBox" />
<TextBlock x:Name="tb" Text="{Binding ElementName=sourceTBox,Path=Text}" />
在上面的代码中,我们就用到了绑定。但是我个人建议,为了代码简洁,默认的属性和默认的属性配制不需要在代码中重写设置。
所有上面的代码可以优化成下面代码
<TextBox x:Name="sourceTBox" />
<TextBlock x:Name="tb" Text="{Binding Text,ElementName=sourceTBox}" />
绑定表达试中 Path 属性被省略, Path=Text 简写成 Text。为什么可以这样简写,是因为 Binding 类中有一个 带Path 的构造方法。
Wpf 不会引发异常来通知与数据绑定相关的问题,如果绑定的属性不存在,不会收到任何提示,也不能在目标属性显示任何值。
WPF 绑定失败细节的跟踪信息会在 输出窗口 显示
WPF 绑定失败细节的跟踪信息会在 输出窗口 显示
WPF 绑定失败细节的跟踪信息会在 输出窗口 显示
如果要在控件中 显示 参考 Binding 的 TargetNullValue 属性
<TextBlock x:Name="tb" Text="{Binding Text,ElementName=sourceTBox,Mode=TwoWay},TargetNullValue='has error'" />
当设置 Binding.Mode 属性时。WPF 允许使用 5 个 system.windows.data.BindingMode 枚举值中的任何一个。代码如下,其中的 Mode=TwoWay 就是设置绑定模式
<TextBlock x:Name="tb" Text="{Binding Text,ElementName=sourceTBox,Mode=TwoWay}" />
system.windows.data.BindingMode 枚举值:
枚举名称 | 说明 |
---|---|
OneWay | 当源属性变化时更新目标属性 |
TwoWay | 当源属性变化时更新目标属性 ,当目标属性 变化时更新源属性 |
OneTime | 最初设定源属性时更新目标属性,后期的变化都被忽略 ,如果知道源属性不会变化,可以使用这种模式,降低开销 |
OneWayToSource | 与OneWay 类似,但方向相反,当目标属性变化时更新源属性,有点向后传递,但目标属性永远不会被更新 |
Default | 此类绑定依赖于目标属性,即可以是双向(对于用户可以设置的属性,如TextBlock.Text,) 也可以是单向,除非明确指明一种模式,否则都采用此种模式 |
Binding binding = new Binding();
binding.Source = this.sourceTBox; //指向源对像 this 指向的当前的Window 对像 的 sourceTBox 对像 ,sourceTBox 是对像的名称,即(x:Name="**")
//binding.Source = this; //指向源对像 this 指向的当前的Window 对像 ,也可
binding.Path = new PropertyPath("Text");
this.tb.SetBinding(TagProperty, binding);
使用 BindingOperations
Binding binding = new Binding();
binding.Path = new PropertyPath("Text");
//BindingOperations.SetBinding(this, TitleProperty, binding);
BindingOperations.SetBinding(this,TitleProperty,binding);
使用代码 获取绑定
Binding binding = BindingOperations.GetBinding(this.tb, TextBlock.TextProperty);
//获取绑定以后可以修改 bindig 的属性
//binding.Mode = BindingMode.TwoWay;
//...
//修改过后可以重先设置绑定
//BindingOperations.SetBinding(this.tb,TextProperty,binding);
更实用的 BindingExpression 对像
BindingExpression expression = BindingOperations.GetBindingExpression(this.tb, TextBlock.TextProperty);
//get source element 获取源对像
TextBox textBox =(TextBox) expression.ResolvedSource;
//get any data you need from the source element
string name = textBox.Name;
// expression.ResolvedSource 获取绑定对像的引用
BindingExpression 更加实用的信息,去源码里查看
<CheckBox x:Name="cb1"
Visibility="Collapsed"
IsChecked="False"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Width="50" Height="30"
BorderThickness="0"
IsVisibleChanged="cb1_IsVisibleChanged" />
<TextBox x:Name="sourceTBox" />
<TextBlock x:Name="tb"
Text="{Binding Text,ElementName=sourceTBox,Mode=TwoWay}"
Tag="{Binding Content ,ElementName=cb1,Mode=OneWay}"
Visibility="{Binding IsChecked,ElementName=cb1,Converter={StaticResource Boolean2VisibilityConverter}}"
/>
使用代码
<TextBlock x:Name="tb" Text="{Binding Text,ElementName=sourceTBox,Mode=TwoWay,UpdateSourceTrigger=Default}"
UpdateSourceTrigger 枚举值
名称 | 说明 |
---|---|
PropertyChanged | 属性发生变化时更新 |
LostFous | 失去焦点时更新 |
Explicit | 调用 BindingExpress.UpdateSource()时更新 |
Defeat | 根据属性的元数据确定更新行为(FrameworkPropertyMetadata.DefaultUpdateSourceTriggere) 大多数默认行为 是PropertyChanged 但TextBox.Text 默认行为是 LostFocus |
作用 :避免过分频繁的触发操作,导致频繁更新UI。
使用 Binding 对像的 Delay 属性。等待数毫秒之后再提交更新。
使用代码
<TextBlock x:Name="tb" Text="{Binding Text,ElementName=sourceTBox,Mode=TwoWay,Delay=500}" />
500 毫秒后再更新。
在项目开发中,大量的数据绑定是将元素达到到数据对像。从而可以显示 从 数据库或者文件 中提取的数据,从而需要绑定到非元素的对象中。
使用代码
<TextBlock Text="{Binding Source,Source={x:Static SystemFonts.CaptionFontFamily}}"/>
第一个 Source 是 Path 属性的值
RelativeSource 属性可以根据相对目标对像的关系指向源对像,例如,可以使用RelativeSource 属性将元素绑定 自身 或 父元素。
设置 Binding.RelativeSource 属性 需要 RelativeSource 对像。语法会变得更加复杂。
<TextBlock >
<TextBlock.Text>
<Binding Path="Title">
<Binding.RelativeSource>
<RelativeSource Mode="FindAncestor" AncestorType="{x:Type Window}" AncestorLevel="1" />
</Binding.RelativeSource>
</Binding>
</TextBlock.Text>
</TextBlock>
<!--以上代码可以简写成如下-->
<TextBlock Text="{Binding Title,RelativeSource={RelativeSource Mode=FindAncestor,AncestorLevel=1,AncestorType={x:Type Window}}}" />
<!--一般一个窗口只有一个Window 对像,可以再次简写-->
<TextBlock Text="{Binding Title,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type Window}}}" />
<TextBlock >
<TextBlock.ToolTip>
<Binding Path="Text">
<Binding.RelativeSource>
<RelativeSource Mode="Self" />
</Binding.RelativeSource>
</Binding>
</TextBlock.ToolTip>
</TextBlock>
<!--以上代码可以简写成如下-->
<TextBlock Text="{Binding Text,RelativeSource={RelativeSource Mode=Self}}" />
<TextBlock >
<TextBlock.ToolTip>
<Binding Path="Text">
<Binding.RelativeSource>
<RelativeSource Mode="PreviousData" />
</Binding.RelativeSource>
</Binding>
</TextBlock.ToolTip>
</TextBlock>
<!--以上代码可以简写成如下-->
<TextBlock Text="{Binding Text,RelativeSource={RelativeSource Mode=PreviousData}}" />
此时 Path=Text ,Text 是数据列表中的前一个对像的属性,不一定是依赖项属性,这种模式只会在列表中使用
以上代码不是真实使用时的代码,只是说明 写法。
只有当绑定位于控件模板() 或 数据模板() 内部时,这种模式才能工作。
<Button x:Name="Btn1" Content="Button" Background="Blue" Tag="/themes/img/snend.png">
<Button.Style>
<Style TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="PART_border" Background="{Binding Background,RelativeSource={RelativeSource Mode=TemplatedParent}}">
<StackPanel Orientation="Horizontal">
<Image x:Name="img" Source="{Binding Tag,RelativeSource={RelativeSource Mode=TemplatedParent}}"/>
<TextBlock x:Name="txt" Text="{Binding Content,RelativeSource={RelativeSource Mode=TemplatedParent}}"/>
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Button.Style>
</Button>
我们可以如下理解:
<Button x:Name="Btn1" Content="Button" Background="Blue" Tag="/themes/img/snend.png">
<Button.Style>
<Style TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="PART_border" Background="{TemplateBinding Background}">
<StackPanel Orientation="Horizontal">
<Image x:Name="img" Source="{TemplateBinding Tag}"/>
<TextBlock x:Name="txt" Text="{TemplateBinding Content}"/>
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Button.Style>
</Button>
绑定表达式的代码明显简洁了很多。
<TextBlock Text="{Binding Version}" />
Wpf就从当前元素开始在元素树中向上查找。检查每一个元素的DataContent属性,并使用 第一个非空的DataContent 属性 所引用的对像的 Version 属性。
如果 TextBlock的Text 直到 Window 对像DataContent 属性引用一个对像不为空,TextBlock的Text 就绑定到 Window 对像DataContent 属性引用对像的 Version 属性上。
//Window 对像DataContent 属性引用对像 SystemVersion
public class SystemVersion{
public int Code { get; set; }
public String Version { get; set; }
}
//设置 Window 对像DataContent 属性
this.DataContext = new SystemVersion()
{
Code = 103,
Version = "V1.0.3"
};
绑定代码
<TextBlock Text="{Binding Version}" />