WPF---数据绑定(一)
一、何为数据绑定
场景:考虑一个Window上有一个TextBox和一个Slider两个元素,当我们拖动滑动条的时候,会在TextBox中显示当前滑动条的数值;当我们在TextBox中输入一个有效值,滑动条
中的滑块会滑到TextBox中输入的值所对应的位置。
定义:数据绑定可以理解为两个对象之间的一种关联,对象中的某个属性总是保持同步于另个对象的某个属性值。我们可以形象的把绑定比作一个桥梁,它负责同步桥头两侧的物体。
保持同步的数据元素必须是属性,一个叫源属性,一个叫目标属性;
目标属性必须是一个依赖属性。
二、如何绑定元素对象
关于上面滑动条和文本框的绑定,我们可以用以下Xaml代码实现:
<Window x:Class="BindingDemo1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:BindingDemo1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<StackPanel>
<TextBox Name="tbx" Text="{Binding Path=Value, ElementName=sldrSlider}" ></TextBox>
<Slider Name="sldrSlider" Minimum="0" Maximum="100"></Slider>
</StackPanel>
</Grid>
</Window>
等价的后台代码实现如下:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data; namespace BindingDemo1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
// Binding binding = new Binding() { ElementName = "sldrSlider",Path= new PropertyPath("Value")};
Binding binding = new Binding("Value") { ElementName = "sldrSlider" };
tbx.SetBinding(TextBox.TextProperty, binding);
}
}
}
后台代码主要完成了以下功能:
1)创建一个binding对象;
2)设置了binding对象的Source和Path值;
3)调用了目标(textbox)的SetBinding方法创建一个binding表达式,它连接了binding对象和目标依赖属性。

三、数据绑定的方向
我们可以通过设置Binding对象的Mode属性来控制数据绑定的方向。
OneWay:数据源改变时,更新目标;
TwoWay:双向更新;
OneWayToSource:目标改变时,更新数据源;
OneTime:只更新目标一次,使用数据源的初值,以后目标不再被更新;
Default:使用目标的默认绑定模式。
四、触发器---更新数据源的时机
仍然考虑上面滑动条和文本框的绑定关系,我们会发现当文本框的数值改变后,滑动条的滑块不会立即改变,而是在文本框失去焦点的时候,才会改变。
这就涉及到当目标属性变化的时候,数据源如何以及何时变化。
关于数据的更新方向和时机,可以参见下图:

当目标依赖属性发生变化,我们可以利用Binding对象的UpdateSourceTrigger属性来控制何时更新数据源,UpdateSourceTrigger属性值包括以下:

注:UpdateSourceTrigger属性值不影响目标的更新方式,它仅仅控制TwoWay模式或OneWayToSource模式的绑定更新源的方式。
而文本框正是使用LostFocus方式从目标向源进行更新的。
如果要完全控制源对象的更新时机,则可以选择UpdateSourceTrigger.Explicit模式。
此时就需要额外编写代码手动触发更新。可以添加一个Apply按钮,并在按钮的Click事件处理程序中调用BindingExpression.UpdateSource方法立即更新数据源。
参考代码以下:
1 <Window x:Class="BindingDemo1.MainWindow"
2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
6 xmlns:local="clr-namespace:BindingDemo1"
7 mc:Ignorable="d"
8 Title="MainWindow" Height="350" Width="525">
9 <Grid>
10 <StackPanel>
11 <TextBox Name="tbx" Text="{Binding Path=Value, ElementName=sldrSlider,UpdateSourceTrigger=Explicit}" ></TextBox>
12 <Slider Name="sldrSlider" Minimum="0" Maximum="100"></Slider>
13 <Button Height="30" Width="100" Content="Apply" Click="Button_Click"></Button>
14 </StackPanel>
15 </Grid>
16 </Window>
1 using System.Windows;
2 using System.Windows.Controls;
3 using System.Windows.Data;
4
5 namespace BindingDemo1
6 {
7 /// <summary>
8 /// Interaction logic for MainWindow.xaml
9 /// </summary>
10 public partial class MainWindow : Window
11 {
12 public MainWindow()
13 {
14 InitializeComponent();
15 //Binding binding = new Binding() { ElementName = "sldrSlider",Path= new PropertyPath("Value")};
16 //Binding binding = new Binding("Value") { ElementName = "sldrSlider" ,UpdateSourceTrigger=UpdateSourceTrigger.};
17 //tbx.SetBinding(TextBox.TextProperty, binding);
18 }
19
20 private void Button_Click(object sender, RoutedEventArgs e)
21 {
22 //获得应用于文本框上的绑定
23 BindingExpression be = tbx.GetBindingExpression(TextBox.TextProperty);
24 //调用UpdateSource更新源对象
25 be.UpdateSource();
26 }
27 }
28 }
五、转换器
上面的例子中,当拖动滑动条的时候,文本框中显示的数字会显示好多位小数,现在我们想让在文本框中只显示两位小数,这时候就需要转换器来实现了。
定义:转化器是一个类,用于拦截数据源和目标之间的数据,拦截之后,就可以按照我们的意愿对数据进行操作。
转换器包括单值转换器和多值转换器。单值转换器需要实现IValueConverter接口,多值转换器需要实现IMultiValueConverter接口。
对于上面的需求,我们可以使用单值转换器,参考代码如下:
1 using System;
2 using System.Globalization;
3 using System.Windows;
4 using System.Windows.Controls;
5 using System.Windows.Data;
6
7 namespace BindingDemo1
8 {
9 /// <summary>
10 /// Interaction logic for MainWindow.xaml
11 /// </summary>
12 public partial class MainWindow : Window
13 {
14 public MainWindow()
15 {
16 InitializeComponent();
17 //Binding binding = new Binding() { ElementName = "sldrSlider",Path= new PropertyPath("Value")};
18 //Binding binding = new Binding("Value") { ElementName = "sldrSlider" ,UpdateSourceTrigger=UpdateSourceTrigger.};
19 //tbx.SetBinding(TextBox.TextProperty, binding);
20 }
21
22 private void Button_Click(object sender, RoutedEventArgs e)
23 {
24 //获得应用于文本框上的绑定
25 BindingExpression be = tbx.GetBindingExpression(TextBox.TextProperty);
26 //调用UpdateSource更新源对象
27 be.UpdateSource();
28 }
29 }
30 public class SliderValue2StringConverter:IValueConverter
31 {
32 public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
33 {
34 double valueFromSource = (double)value;
35 return valueFromSource.ToString("F2");//保留两位小数
36 }
37
38 public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
39 {
40 throw new NotImplementedException("Method ConvertBack not implemented");
41 }
42 }
43 }
1 <Window x:Class="BindingDemo1.MainWindow"
2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
6 xmlns:local="clr-namespace:BindingDemo1"
7 mc:Ignorable="d"
8 Title="MainWindow" Height="350" Width="525">
9 <Window.Resources>
10 <local:SliderValue2StringConverter x:Key="s2vCvt"></local:SliderValue2StringConverter>
11 </Window.Resources>
12 <Grid>
13 <StackPanel>
14 <TextBox Name="tbx" Text="{Binding Path=Value, ElementName=sldrSlider,UpdateSourceTrigger=Explicit,Converter={StaticResource ResourceKey=s2vCvt}}" ></TextBox>
15 <Slider Name="sldrSlider" Minimum="0" Maximum="100"></Slider>
16 <Button Height="30" Width="100" Content="Apply" Click="Button_Click"></Button>
17 </StackPanel>
18 </Grid>
19 </Window>
现在考虑以下场景,我们有一个椭圆,椭圆的颜色是根据RGB三个不同的分量变化的,我们让三个滑动条分别控制RGB三个分量,下面就用多值转换器进行实现。
1 using System;
2 using System.Globalization;
3 using System.Windows;
4 using System.Windows.Controls;
5 using System.Windows.Data;
6 using System.Windows.Media;
7
8 namespace BindingDemo1
9 {
10 /// <summary>
11 /// Interaction logic for MainWindow.xaml
12 /// </summary>
13 public partial class MainWindow : Window
14 {
15 public MainWindow()
16 {
17 InitializeComponent();
18 //Binding binding = new Binding() { ElementName = "sldrSlider",Path= new PropertyPath("Value")};
19 //Binding binding = new Binding("Value") { ElementName = "sldrSlider" ,UpdateSourceTrigger=UpdateSourceTrigger.};
20 //tbx.SetBinding(TextBox.TextProperty, binding);
21 }
22
23 private void Button_Click(object sender, RoutedEventArgs e)
24 {
25 //获得应用于文本框上的绑定
26 BindingExpression be = tbx.GetBindingExpression(TextBox.TextProperty);
27 //调用UpdateSource更新源对象
28 be.UpdateSource();
29 }
30 }
31 public class SliderValue2StringConverter:IValueConverter
32 {
33 public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
34 {
35 double valueFromSource = (double)value;
36 return valueFromSource.ToString("F2");//保留两位小数
37 }
38
39 public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
40 {
41 throw new NotImplementedException("Method ConvertBack not implemented");
42 }
43 }
44 public class Rgb2ColorConverter : IMultiValueConverter
45 {
46 //正向修改,整合颜色值
47 public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
48 {
49 if (values == null || values.Length < 3)
50 return null;
51 byte r = System.Convert.ToByte(values[0]);
52 byte g = System.Convert.ToByte(values[1]);
53 byte b = System.Convert.ToByte(values[2]);
54 Color myColor = Color.FromRgb(r, g, b);
55 SolidColorBrush myBrush = new SolidColorBrush(myColor);
56 return myBrush;
57 }
58 public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
59 {
60 throw new NotImplementedException("Method ConvertBack not implemented");
61 }
62
63 }
64 }
1 <Window x:Class="BindingDemo1.MainWindow"
2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
6 xmlns:local="clr-namespace:BindingDemo1"
7 mc:Ignorable="d"
8 Title="MainWindow" Height="350" Width="525">
9 <Window.Resources>
10 <local:SliderValue2StringConverter x:Key="s2vCvt"></local:SliderValue2StringConverter>
11 </Window.Resources>
12 <Grid>
13 <Grid.ColumnDefinitions>
14 <ColumnDefinition Width="191*"/>
15 <ColumnDefinition Width="326*"/>
16 </Grid.ColumnDefinitions>
17 <Grid.RowDefinitions>
18 <RowDefinition Height="111*"/>
19 <RowDefinition Height="209*"/>
20 </Grid.RowDefinitions>
21 <StackPanel>
22 <TextBox Name="tbx" Text="{Binding Path=Value, ElementName=sldrSlider,UpdateSourceTrigger=Explicit,Converter={StaticResource ResourceKey=s2vCvt}}" ></TextBox>
23 <Slider Name="sldrSlider" Minimum="0" Maximum="100"></Slider>
24 <Button Height="30" Width="100" Content="Apply" Click="Button_Click"></Button>
25
26 </StackPanel>
27 <StackPanel Grid.Column="1">
28 <StackPanel Orientation="Horizontal">
29 <Label Content="R:"></Label>
30 <Slider Name="sldR" Foreground="Red" Width="300" Minimum="0" Maximum="255" Ticks="1"></Slider>
31 </StackPanel>
32 <StackPanel Orientation="Horizontal">
33 <Label Content="G:"></Label>
34 <Slider Name="sldG" Foreground="Red" Width="300" Minimum="0" Maximum="255" Ticks="1"></Slider>
35 </StackPanel>
36 <StackPanel Orientation="Horizontal">
37 <Label Content="B:"></Label>
38 <Slider x:Name="sldB" Foreground="Red" Width="300" Minimum="0" Maximum="255" Ticks="1"/>
39 </StackPanel>
40 <StackPanel Orientation="Horizontal">
41 <Label Content="O:"></Label>
42 <Slider Name="sldO" Foreground="Red" Width="300" Minimum="0" Maximum="1" Ticks="0.1" Value="0.5"></Slider>
43 </StackPanel>
44
45 </StackPanel>
46 <Ellipse Grid.Row="1" Grid.Column="1" Stroke="Pink">
47 <Ellipse.Resources>
48 <local:Rgb2ColorConverter x:Key="colorCvt"></local:Rgb2ColorConverter>
49 </Ellipse.Resources>
50 <Ellipse.Fill>
51 <MultiBinding Converter="{StaticResource colorCvt}">
52 <Binding ElementName="sldR" Path="Value"></Binding>
53 <Binding ElementName="sldG" Path="Value"></Binding>
54 <Binding ElementName="sldB" Path="Value"></Binding>
55 </MultiBinding>
56 </Ellipse.Fill>
57 <Ellipse.Opacity>
58 <Binding Path="Value" ElementName="sldO" >
59
60 </Binding>
61 </Ellipse.Opacity>
62 </Ellipse>
63 </Grid>
64 </Window>

六、绑定的删除
我们可以使用类BindingOperations中的以下函数来删除绑定
public static void ClearAllBindings(DependencyObject target);
public static void ClearBinding(DependencyObject target, DependencyProperty dp);
WPF---数据绑定(一)的更多相关文章
- WPF 数据绑定Binding
什么是数据绑定? Windows Presentation Foundation (WPF) 数据绑定为应用程序提供了一种简单而一致的方法来显示数据以及与数据交互. 通过数据绑定,您可以对两个不同对象 ...
- WPF数据绑定Binding(二)
WPF数据绑定Binding(二) 1.UI控件直接的数据绑定 UI对象间的绑定,也是最基本的形式,通常是将源对象Source的某个属性值绑定 (拷贝) 到目标对象Destination的某个属性上. ...
- WPF——数据绑定(一)什么是数据绑定
注意:本人初学WPF,文中可能有表达或者技术性问题,欢迎指正!谢谢! 一:什么是数据绑定? “Windows Presentation Foundation (WPF) 数据绑定为应用程序提供了一种简 ...
- 剖析WPF数据绑定机制
引言 WPF框架采取的是MVVM模式,也就是数据驱动UI,UI控件(Controls)被严格地限制在表示层内,不会参与业务逻辑的处理,只是通过数据绑定(Data Binding)简单忠实地表达与之绑定 ...
- WPF 10天修炼 第十天- WPF数据绑定
WPF数据绑定 数据绑定到元素属性是将源对象指定为一个WPF元素,并且源属性是一个依赖属性,依赖属性内置了变更通知.当改变源对象依赖属性值之后,绑定目标可以立即得到更新,开发人员不需要手动编写响应事件 ...
- 微软原文翻译:适用于.Net Core的WPF数据绑定概述
原文链接,大部分是机器翻译,仅做了小部分修改.英.中文对照,看不懂的看英文. Data binding overview in WPF 2019/09/19 Data binding in Windo ...
- C#-WPF数据绑定基础(一)
前言:WPF数据绑定技术有效的提高了程序的容错率,可以最大程度的保持程序的健壮性,从而降低程序在使用过程中崩掉的可能性. 接下来,我将分享一下我在写测量程序过程中所用到的数据绑定方面的知识 首先,我所 ...
- C#WPF数据绑定模板化操作四步走
前言:WPF数据绑定对于WPF应用程序来说尤为重要,本文将讲述使用MVVM模式进行数据绑定的四步走用法: 具体实例代码如下: 以下代码仅供参考,如有问题请在评论区留言,谢谢 1 第一步:声明一个类用来 ...
- WPF 数据绑定 1_1 基础知识&绑定到元素属性
A.数据绑定基础: 数据源对象:WPF将从该对象中提取信息,交由目标对象进行显示. 目标对象:从数据源中提取信息,并赋给该对象的属性. B.绑定到元素属性 最简单的绑定情形则是将一个源对象指定为一个W ...
- WPF 数据绑定基础
纯理论,可能会枯燥. .net 技术群: 199281001 ,欢迎加入. 1.目标对象一定是派生自DependencyObject的对象,并且目标属性必须是依赖属性,否则数据绑定操作将会失 败. ...
随机推荐
- python encode decode
Python encode()encode() 方法以 encoding 指定的编码格式编码字符串.errors参数可以指定不同的错误处理方案.写法:str.encode(encoding='UTF- ...
- win10禁止粘滞键 禁止按5次shift开启粘滞键
如果你感觉粘滞键的快捷键影响了你的使用或想强行更改连续按5次上档键的指向的话,建议用你需要的程序替换%windir%\system32文件夹下面的sethc.exe @echo offclsdel / ...
- 【超值分享】为何写服务器程序需要自己管理内存,从改造std::string字符串操作说起。。。
服务器程序为何要进行内存管理,管中窥豹,让我们从string字符串的操作说起...... new/delete是用于c++中的动态内存管理函数,而malloc/free在c++和c中都可以使用,本质上 ...
- odoo14里面的消息机制
odoo里面 字段追踪.消息通知机制: 一.使用方式:1.在定义模型的py文件里继承mail模型 class DemoModle(models.Model): """ ...
- Flask 之linux部署
1.装python > `[root ~]# yum install gcc [root ~]# wget https://www.python.org/ftp/python/3.6.5/Pyt ...
- Floyd弗洛伊德算法
先看懂如何使用 用Java实现一个地铁票价计算程序 String station = "A1 A2 A3 A4 A5 A6 A7 A8 A9 T1 A10 A11 A12 A13 T2 A1 ...
- Linux扩展分区和文件系统
磁盘分区 linux也与windows一样,为了使用全部的磁盘空间,需要先对磁盘分区:如果所有分区的总容量小于磁盘容量,说明磁盘还有未分配空间,这个时候会对磁盘造成浪费.需要增加一个新的分区来将全部空 ...
- Java8 Lambda表达式(二)
目录 一.Java8 内置的四大核心函数式接口 1. 消费型接口 Consumer 2. 供给型接口 Supplier 3. 函数型接口 Function 4.断言型接口 Predicate 二.方法 ...
- 2019.06.28 MERGE INTO备忘
--保存主表 MERGE INTO dbo.DeliveryReceiving AS t USING @ReceiveMainDt AS s ON t.Id=s.id WHEN MATCHED THE ...
- Java8新特性(二)之函数式接口
.subTitle { background: rgba(51, 153, 0, 0.66); border-bottom: 1px solid rgba(0, 102, 0, 1); border- ...