说到数据绑定,其实这并不是一个新的玩意儿。了解asp.net的朋友都知道,在asp.net中已经用到了这个概念,例如Repeater等的数据绑定。那么,在WPF中的数据绑定相比较传统的asp.net中的数据绑定又有哪些优点呢?

1)具有双向性,即从源到目标是双向的
2)及时更新,源发生改变时,能够及时更新UI
3)Validation和Converter,前者保证数据的合法性,后者保证数据的有效性
接下来,我们将从这么几个方面来说明:Binding对象(对应xaml中的Binding扩展标记)、Binding的Path以及Source、Validation及Converter和MultiBinding。

1.Binding对象

在Binding对象中,主要成员可以分为这么几类:
1)路径:Path属性和XPath属性
2)源:Source、RelativeSource和ElementName
3)更新通知:NotifyOnSourceUpdated、NotifyOnTargetUpdated和NotifyOnValidationError
4)转换器:Converter、ConverterCulture和ConverterParameter
5)验证:ValidatesOnDataErrors、ValidatesOnExceptions、ValidatesOnNotifyDataErrors和ValidationRules
6)绑定方式:Mode,BindingMode枚举类型:TwoWay,OneWay,OneTime,OneWayToSource和Default
需要注意的是:Binding的目标必须是依赖对象的某个依赖属性。

2.Binding的Path以及Source

对于Binding的Path及Source,并非要是依赖属性及依赖对象。几乎任何一个对象都可以作为Binding的Source,主要有普通CLR对象、ado.net对象、XML、Linq、依赖对象、容器的DataContext、RelativeSource和ObjectDataProvider等。
而Path就是普通CLR对象、容器的DataContext、RelativeSource和Linq的某个属性、
ado.net对象的某个字段、依赖对象的某个依赖属性和ObjectDataProvider的某个方法名。
这里需要注意一下几点:

1)有Path没Source,将去找其父元素有该Path的DataContext;
2)有Source没Path,则将Source也作为其Path;

3)无Source无Path,则将其父元素的DataContext既作为Source也作为Path。

关于Binding的Source这里只说下Xml、Linq to Xml和ObjectDataProvider,其它几种略过。

2.1使用Xml作为Binding Source

首先,我们来准备xml数据,命名为Students.xml,如下:

<?xml version="1.0" encoding="utf-8" ?>
<Students>
<Student ID="1">
<Name>Jello</Name>
<Score>80</Score>
</Student>
<Student ID="2">
<Name>Taffy</Name>
<Score>100</Score>
</Student>
</Students>

Xaml代码如下:

<Window x:Class="DataBindingDemo.XmlWindow1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="XmlWindow1" Height="300" Width="300">
<Grid>
<ListBox x:Name="lb">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="tbID" Text="{Binding XPath=@ID}" Width="20" Foreground="Red"/>
<TextBlock x:Name="tbName" Text="{Binding XPath=Name}" Width="40" Foreground="Green"/>
<TextBlock x:Name="tbScore" Text="{Binding XPath=Score}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>

cs代码如下:

    /// <summary>
/// XmlWindow1.xaml 的交互逻辑
/// </summary>
public partial class XmlWindow1 : Window
{
public XmlWindow1()
{
InitializeComponent();
/*第一种写法:
XmlDocument doc = new XmlDocument();
doc.Load(@"./Students.xml");
XmlDataProvider xdp = new XmlDataProvider();
xdp.Document = doc;
xdp.XPath = "/Students/Student";
this.lb.SetBinding(ListBox.ItemsSourceProperty, new Binding(".") { Source = xdp });
*/
//第二种写法:
XmlDataProvider xdp = new XmlDataProvider();
xdp.Source = new Uri(@"F:\dotnet\WPF\学习\WPF\Demo\WpfDemo\DataBindingDemo\Students.xml");
xdp.XPath = "/Students/Student";
this.lb.DataContext = xdp;
this.lb.SetBinding(ListBox.ItemsSourceProperty, new Binding());
}
}

第一种写法借助于XmlDataProvider的Document属性,第二种写法借助于XmlDataProvider的Source属性。

如果想直接在Xaml代码里面来直接使用XmlDataProvider来进行绑定的话,需要将Xml数据放在<x:XData>...</x:XData>标签内,代码如下:

<Window x:Class="DataBindingDemo.XmlWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="XmlWindow" Height="300" Width="300">
<Window.Resources>
<XmlDataProvider x:Key="xdp" XPath="Students/Student">
<x:XData>
<Students xmlns="">
<Student ID="1">
<Name>Jello</Name>
<Score>80</Score>
</Student>
<Student ID="2">
<Name>Taffy</Name>
<Score>100</Score>
</Student>
</Students>
</x:XData>
</XmlDataProvider>
</Window.Resources>
<Grid>
<ListBox x:Name="lb" ItemsSource="{Binding Source={StaticResource xdp}}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding XPath=@ID}" Width="20" Foreground="Red"/>
<TextBlock Text="{Binding XPath=Name}" Width="40" Foreground="Green"/>
<TextBlock Text="{Binding XPath=Score}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>

效果如下:

2.2使用Linq to Xml作为Binding Source

在使用Linq to Xml作为Binding Source之前,我们当然需要准备model,这里创建一个Student实体类:

    public class Student
{
public int ID { get; set; }
public string Name { get; set; }
public int Score { get; set; }
}

Xaml代码如下:

<Window x:Class="DataBindingDemo.XmlWindow2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="XmlWindow2" Height="300" Width="300">
<Grid>
<ListBox x:Name="lb">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="tbID" Text="{Binding Path=ID}" Width="20" Foreground="Red"/>
<TextBlock x:Name="tbName" Text="{Binding Path=Name}" Width="40" Foreground="Green"/>
<TextBlock x:Name="tbScore" Text="{Binding Path=Score}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>

cs代码如下:

    /// <summary>
/// XmlWindow2.xaml 的交互逻辑
/// </summary>
public partial class XmlWindow2 : Window
{
public XmlWindow2()
{
InitializeComponent(); XDocument doc = XDocument.Load(@"F:\dotnet\WPF\学习\WPF\Demo\WpfDemo\DataBindingDemo\Students.xml");
this.lb.ItemsSource = from e in doc.Descendants("Student")
select new Student
{
ID = Int32.Parse(e.Attribute("ID").Value),
Name = e.Element("Name").Value,
Score = Int32.Parse(e.Element("Score").Value)
};
}
}

2.3使用ObjectDataProvider作为Binding Source

其他对象都是针对属性作为Path的情况,而ObjectDataProvider对象主要是针对方法。所以,我们先准备一个具有Add方法的Calculate类:

    public class Calculate
{
public double Add(string d1, string d2)
{
double i, j;
if (double.TryParse(d1, out i) && double.TryParse(d2, out j))
return i + j;
else
return 0;
}
}

Xaml代码如下:

<Window x:Class="DataBindingDemo.ODPWindow1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ODPWindow1" Height="300" Width="300">
<Grid>
<StackPanel>
<TextBox x:Name="tb1"/>
<TextBox x:Name="tb2"/>
<TextBox x:Name="tbResult"/>
</StackPanel>
</Grid>
</Window>

cs代码如下:

    /// <summary>
/// ODPWindow1.xaml 的交互逻辑
/// </summary>
public partial class ODPWindow1 : Window
{
public ODPWindow1()
{
InitializeComponent(); ObjectDataProvider odp = new ObjectDataProvider();
odp.ObjectInstance = new Calculate();
odp.MethodName = "Add";
odp.MethodParameters.Add("0");
odp.MethodParameters.Add("0"); this.tb1.SetBinding(TextBox.TextProperty, new Binding("MethodParameters[0]")
{
Source = odp,
BindsDirectlyToSource = true,
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
});
this.tb2.SetBinding(TextBox.TextProperty, new Binding("MethodParameters[1]")
{
Source = odp,
BindsDirectlyToSource = true,
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
});
this.tbResult.SetBinding(TextBox.TextProperty, new Binding(".")
{
Source = odp
});
}
}

效果如下:

3.Binding的Converter

数据在Binding的Target端和Source端交换时,经常会出现类型或者格式不一致的情况,这时候,我们就可以使用Converter来处理。

WPF内置了许多的Converter,例如:

<Grid.Background>
Red
</Grid.Background>

Backgroud属性是Brush抽象类型,而我们只是用一个Red字符串赋值就能达到效果,这是内置的从String类型到SolidColorBrush类型的Converter。

我们也可以实现自己的Converter,只要实现IValueConverter接口即可。

4.Binding的Validation

数据在Binding的Target端和Source端交换时,除了经常出现类型或者格式不一致,还出现数据不合法的情况。为了避免脏数据的出现,需要在交换前进行Validate。例如:

<StackPanel>
<TextBox x:Name="tb" Text="{Binding Value,ElementName=slider,UpdateSourceTrigger=PropertyChanged}"/>
<Slider x:Name="slider" Minimum="0" Maximum="99" />
</StackPanel>

这里,我们要实现的效果是在TextBox中输入一个0到99之间的数字,Slider会划到相应位置,若输入的数字不在该范围,则TextBox提示数据不合法。

Xaml代码如下:

<StackPanel>
<TextBox x:Name="tb" />
<Slider x:Name="slider" Minimum="0" Maximum="200" />
</StackPanel>

cs代码如下:

    /// <summary>
/// ConverterWnd.xaml 的交互逻辑
/// </summary>
public partial class ConverterWnd : Window
{
public ConverterWnd()
{
InitializeComponent(); Binding binding = new Binding("Value")
{
Source = this.slider,
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
};
RangeValidation rv = new RangeValidation();
rv.ValidatesOnTargetUpdated = true;//验证Source
binding.NotifyOnValidationError = true;//触发Validation.ErrorEvent
binding.ValidationRules.Add(rv);
this.tb.SetBinding(TextBox.TextProperty, binding);
this.tb.AddHandler(Validation.ErrorEvent, new RoutedEventHandler(NotifyError));
}
protected void NotifyError(object sender, RoutedEventArgs e)
{
TextBox tb = sender as TextBox;
if (tb != null)
{
if (Validation.GetErrors(tb).Count > 0)
tb.ToolTip = Validation.GetErrors(tb)[0].ErrorContent.ToString();
}
}
}
public class RangeValidation : ValidationRule
{
public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
{
double d;
if (double.TryParse(value.ToString(), out d))
{
if (d >= 0 && d <= 99)
return new ValidationResult(true, null);
}
return new ValidationResult(false, "数据不合法");
}
}

这里将Slider的最大值设为了200,当其值大于99时,由于ValidatesOnTargetUpdate=true,所以也会路由Validation.ErrorEvent事件。

效果如下:

其实,当未添加验证时,Slider的CoerceValue会强制处理。

5.MultiBinding多路绑定

经常会遇到这样的需求,要求显示“开始日期 -- 结束日期”这样的格式,这时候比较好的做法就是使用MultiBinding,当然,你也可以重新定义一个属性。

Xaml代码如下:

<Grid>
<StackPanel>
<TextBlock Text="{Binding Name}"/>
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0:yyyy-MM-dd}至{1:yyyy-MM-dd}">
<Binding Path="StartDate" />
<Binding Path="EndDate" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</StackPanel>
</Grid>

cs代码如下:

    /// <summary>
/// MultiBindingWnd.xaml 的交互逻辑
/// </summary>
public partial class MultiBindingWnd : Window
{
public MultiBindingWnd()
{
InitializeComponent(); Fruit fruit = new Fruit() { Name = "Apple", StartDate = DateTime.Today, EndDate = DateTime.Today.AddYears(1) };
this.DataContext = fruit;
}
}

这里需要注意两点:

1)MultiBinding添加Binding的顺序会影响Converter

2)MultiBinding的Converter实现的是IMultiValueConverter接口

WPF学习(8)数据绑定 https://www.cnblogs.com/jellochen/p/3541197.html的更多相关文章

  1. WPF学习之数据绑定

    WPF中的数据绑定提供了很强大的功能.与普通的WinForm程序相比,其绑定功能为我们提供了很多便利,例如Binding对象的自动通知/刷新,Converter,Validation Rules,Tw ...

  2. WPF学习笔记 - 数据绑定(在代码中)

    在程序代码里,有两种设置绑定的方法,一种是调用FrameworkElement或FrameContentElement对象的SetBinding实例方法. 例如: Public MainWindow( ...

  3. WPF学习(8)数据绑定

    说到数据绑定,其实这并不是一个新的玩意儿.了解asp.net的朋友都知道,在asp.net中已经用到了这个概念,例如Repeater等的数据绑定.那么,在WPF中的数据绑定相比较传统的asp.net中 ...

  4. WPF学习09:数据绑定之 Binding to List Data

    从WPF学习03:Element Binding我们可以实现控件属性与控件属性的绑定. 从WPF学习07:MVVM 预备知识之数据绑定 我们可以实现控件属性与自定义对象属性的绑定. 而以上两个功能在实 ...

  5. WPF学习07:MVVM 预备知识之数据绑定

    MVVM是一种模式,而WPF的数据绑定机制是一种WPF内建的功能集,两者是不相关的. 但是,借助WPF各种内建功能集,如数据绑定.命令.数据模板,我们可以高效的在WPF上实现MVVM.因此,我们需要对 ...

  6. HBASE学习d端口master:16010(java操作hbase)https://www.cnblogs.com/junrong624/p/7323483.html

    HBase提示已创建表,但是list查询时,却显示表不存在. https://blog.csdn.net/liu16659/article/details/80216085 下载网址 http://a ...

  7. javaWeb学习之 Filter过滤器----https://www.cnblogs.com/xdp-gacl/p/3948353.html

    https://www.cnblogs.com/xdp-gacl/p/3948353.html

  8. wpf学习

    http://www.jikexueyuan.com/course/1231_3.html?ss=1 WPF入门教程系列二——Application介绍 http://www.cnblogs.com/ ...

  9. (转)WPF学习资源整理

    由于笔者正在学习WPF,所以整理出网络中部分WPF的学习资源,希望对同样在学习WPF的朋友们有所帮助. 首推刘铁猛的<深入浅出WPF>系列博文 1.深入浅出WPF(1)——什么是WPFht ...

随机推荐

  1. <scrapy爬虫>爬取校花信息及图片

    1.创建scrapy项目 dos窗口输入: scrapy startproject xiaohuar cd xiaohuar 2.编写item.py文件(相当于编写模板,需要爬取的数据在这里定义) # ...

  2. <数据库>MySQL的安装及安装中存在的问题

    无脑三连: 下载:https://dev.mysql.com/downloads/mysql/5.7.html#downloads 解压:任意目录 添加环境变量:WIN10步骤 我的电脑→属性→高级系 ...

  3. 搞了一宿,弄完了一个POP3协议

    POP3协议和SMTP协议都会了,加上PE文件的读写,APIHOOK,以及远程进程注入,我是不是就可以写个简单点的通过邮件传播的蠕虫病毒了,哈哈哈哈哈哈. 感觉POP3协议挺简单的,比那个该死的SMT ...

  4. RocketMQ补偿方案架构设计

    RocketMQ作为消息中间件,在系统异步化架构中,应用非常广泛.但是我们在享用RocketMQ的同时,也不能百分百完全信赖它.一旦RocketMQ崩溃了,给我们业务带来的也将是毁灭性打击. 因此,我 ...

  5. C/C++操作SQLite

    最近几天在学习sqlite3,颇有点收获,下面介绍一下简单用法:1.先下载sqlite3.h和sqlite3.c(如果不知道怎么下载的话就去www.sqlite.org)如果要编译成lib.则需要用到 ...

  6. Css if hack条件语法

    Css if hack条件语法  <!--[if !IE]><!--> 除IE外都可识别 <!--<![endif]--><!--[if IE]> ...

  7. jquery的each()遍历和ajax传值

    页面展示 JS代码部分 /*功能:删除选中用户信息数据*/ function delUser(){ $("#delU").click(function(){ var unoStr ...

  8. hibernate一对多关系 在一方查询会获得重复数据,重复数量就是多端数据数量用@Fetch(FetchMode.SUBSELECT)解决

    先来看数据表 版块表只有两个数据 板块1是推荐,下边没有子栏目 板块2下边有14个子栏目 在1的一端来查询,发现结果有16条 也就是板块1+版块2+版块2和他的14个子集都列出来了,这明显不对 板块对 ...

  9. mysql基本笔记之一

    1.创建数据库 CREATE DATABASE admin 2.查看数据库 SHOW DATABASES 3.使用数据库 USE admin 4.创建user表 CREATE TABLE user V ...

  10. 二、Python安装和第一个程序

    <1.Python语言介绍1.官方介绍:Python 是一款易于学习且功能强大的编程语言. 它具有高效率的数据结构,能够简单又有效地实现面向对象编程.Python 简洁的语法与动态输入之特性,加 ...