WPF Binding学习(四) 绑定各种数据源

时间:2022-09-14 22:14:11

转自:http://blog.csdn.net/lisenyang/article/details/18312199

1.集合作为数据源

首先我们先创建一个模型类

 public class Student
{
public int ID { get; set; }
public String Name { get; set; }
}

然后我们创建我们的页面布局

 <StackPanel Width="" Height="" HorizontalAlignment="Left">
<ListView Name="listView1">
<ListView.View>
<GridView>
<GridViewColumn Header="编号" DisplayMemberBinding="{Binding ID}" Width=""></GridViewColumn>
<GridViewColumn Header="姓名" DisplayMemberBinding="{Binding Name}" Width=""></GridViewColumn>
</GridView>
</ListView.View>
</ListView> </StackPanel>

在这里我们使用了ListView控件和GridView控件来显示数据,这两个控件从表面来看应该属于同一级别的控件。实际上并非如此!ListView是ListBox的派生类,而GridView是ViewBase的派生类,ListView中的View是一个ViewBase对象,所以,GridView可以做为ListView的View来使用而不能当作独立的控件来使用。这里使用理念是组合模式,即ListView由一个View,但是至于是GridVIew还是其它类型的View,由程序员自己选择。其次,GridView的内容属性是Columns,这个属性是GridViewColumnCollection类型对象。因为XAML支持对内容属性的简写,可以省略<GridView.Columns>这层标签,直接在GridView内部定义<GridViewColumn>对象,GridViewColumn中最重要的一个属性是DisplayBinding(类型是BindingBase),使用这个属性可以指定这一列使用什么样的Binding去关联数据-----这与ListBox有些不同,ListBox使用的是DisplayMemberPath属性(类型是String)。如果想用更复杂的结构来表示这一标题或数据,则可为GridViewColumn设置Head Template和Cell Template,它们的类型都是DataTemplate

接下来下后台代码

 IList<Student> list = new ObservableCollection<Student>()
{
new Student(){ID=,Name="狗娃"},
new Student(){ID=,Name="狗剩"},
new Student(){ID=,Name="铁蛋"}
};
this.listView1.ItemsSource = list;

只需在构造函数中创建对象并绑定到ListView上即可,然后运行就可以看到已经绑定完毕

WPF Binding学习(四)      绑定各种数据源

接下来看一下ObservableCollection这个集合,我们可以看到在这里使用的是ObservableCollection集合而并非平常的List集合,那么为什么呢,因为ObservableCollection集合实现了INotifyCollectionChanged接口,也就是可以双向绑定。

2.ADO.NET中DataTable对象做为数据源

在wpf中,是允许将DataTable直接做为Binding的数据源的,下面以一个例子做为参考

控件还可以用上面的控件,只需该数据源即可

首先先创建一个用于创建DataTable的方法

   public DataTable CreateDt()
{
DataTable dt = new DataTable();
DataColumn[] dc = new DataColumn[]
{
new DataColumn("ID"),
new DataColumn(){ColumnName="Name"}
};
dt.Columns.AddRange(dc);
return dt;
}

然后再构造函数中创建DataTable,赋予值并绑定即可

  DataTable dt = CreateDt();
DataRow dr = dt.NewRow();
dr[] = ;
dr[] = "狗娃";
dt.Rows.Add(dr); dr = dt.NewRow();
dr[] = ;
dr[] = "狗剩";
dt.Rows.Add(dr); dr = dt.NewRow();
dr[] = ;
dr[] = "铁蛋";
dt.Rows.Add(dr);
//将数据源设置为Dt的视图
this.listView1.ItemsSource = dt.DefaultView;

3.使用XML数据作为数据源

WPF提供了两套处理XML的类库:

  1.符合DOM(Document Object Model 文档对象模式)标准类库:XmlDocument.XmlElement,XmlNode等类,这套类型特点中规中矩,功能强大,但也背负了太多的XML传统和复杂

  2.以LINQ(Language-Intergrated Query 语言集成查询)为基础的类库,包括:XDocument,XElement,XNode,XAttribute等类,这套类库特点是可以通过LINQ进行查询和操作,方便快捷

首先使用第一种方案

    先创建一个XML文件

<?xml version="1.0" encoding="utf-8" ?>
<StudentList>
<Student id="">
<Name>狗娃</Name>
</Student>
<Student id="">
<Name>狗剩</Name>
</Student>
<Student id="">
<Name>铁蛋</Name>
</Student>
</StudentList>

然后创建XAML

 <StackPanel Width="" Name="stackPanel1">
<ListView Name="listView1">
<ListView.View>
<GridView>
<GridViewColumn Header="编号" DisplayMemberBinding="{Binding XPath=@id}"> </GridViewColumn>
<GridViewColumn Header="姓名" DisplayMemberBinding="{Binding XPath=Name}"> </GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</StackPanel>

注意:XML绑定不是使用Path,而是XPath

 XmlDocument doc = new XmlDocument();
doc.Load(@"C:\资料\f盘\代码\c#\WPF\TreeView\TestSource\Students.xml");
//通过XmlDataProvider进行绑定数据
XmlDataProvider dp = new XmlDataProvider();
dp.Document = doc;
dp.XPath = @"StudentList/Student";
this.listView1.SetBinding(ListView.ItemsSourceProperty, new Binding() { Source=dp});

绑定XMl使用到了XmlDataProvider,这个类是将XMl做为数据源源的一种快捷方式.XmlDataPrivider有个Source属性,可以使用它直接指定XML文档地址(无论XML文档是存储在本地还是网络位置),所以也可以这么写

 XmlDataProvider dp = new XmlDataProvider();
dp.Source = new Uri(@"C:\资料\f盘\代码\c#\WPF\TreeView\TestSource\Students.xml");
dp.XPath = @"StudentList/Student";
this.listView1.SetBinding(ListView.ItemsSourceProperty, new Binding() { Source=dp});

4.使用LINQ做为数据源

从3.0版本,.NET Framework开始支持LINQ,使用LINQ,可以方便的操作集合对象,LINQ查询结果是一个IEnumerable<T>类型对象,而IEnumerable<T>又派生自IEnumerable,所以可以作为列表控件的Items Source使用。

现在还还用刚开始创建的那个Student模型类和XAML代码,

public class Student
{
public int ID { get; set; }
public String Name { get; set; }
}
<StackPanel Height="" Width="" HorizontalAlignment="Left">
<ListView Name="listView1">
<ListView.View>
<GridView>
<GridViewColumn Header="编号" DisplayMemberBinding="{Binding ID}" Width=""></GridViewColumn>
<GridViewColumn Header="姓名" DisplayMemberBinding="{Binding Name}" Width=""></GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</StackPanel>

我们只需更改数据源即可

 List<Student> stus = new List<Student>()
{
new Student(){ID=,Name="狗娃"},
new Student(){ID=,Name="铁蛋"},
new Student(){ID=,Name="狗剩"}
};
this.listView1.ItemsSource = from stu in stus where stu.Name.StartsWith("狗") select stu;

还可以将数据放在DataTable中

 DataTable dt = CreateDt();
DataRow dr = dt.NewRow();
dr[] = ;
dr[] = "狗娃";
dt.Rows.Add(dr); dr = dt.NewRow();
dr[] = ;
dr[] = "狗剩";
dt.Rows.Add(dr); dr = dt.NewRow();
dr[] = ;
dr[] = "铁蛋";
dt.Rows.Add(dr); this.listView1.ItemsSource = from row in dt.Rows.Cast<DataRow>()
where (row["Name"] as String).StartsWith("狗")
select new Student
{
ID = Convert.ToInt32(row["ID"]),
Name = row["Name"] as String
};

又或者使用XML

 XDocument xd = XDocument.Load(@"C:\资料\f盘\代码\c#\WPF\TreeView\TestSource\Students.xml");
this.listView1.ItemsSource = from ele in xd.Descendants("Student")
where (ele.Elements().First()).Value.StartsWith("狗")
select new Student
{
ID = Convert.ToInt32(ele.Attribute("id").Value),
Name = ele.Elements().First().Value

5.ObjectDataProvider做为数据源

理想情况下,上游程序员将类设计好,使用属性把数据暴露出来,下游程序员将这些类作为Binding的Source,把属性做为Binding的Path来消费。但很难保证一个类的属性都暴露出来,例如需要的数据可能是方法的返回值。而重新设计底层类的风险会比较高,况且有可能引用的类库情况我们不可能更改已经便宜好的类,这时候就需要使用ObjectDataProvider来包装做为Binding源的数据对象。

ObjectDataProvider顾名思义就是把对对象做为数据源提供给Binding。上面使用的XmlDataProvider,这两个类的父类都是DataSourceProvider抽象类。

现在做一个这样例子。

有一个Calculator类,它具有一个加法方法

class Caculate
{
public string Add(string arg1, string arg2)
{
double x = ;
double y = ;
double z = ;
if (double.TryParse(arg1, out x) && double.TryParse(arg2, out y))
{
z = x + y;
return z.ToString();
}
return "Iput Error";
} }

然后在XAML中创建三个TextBox框

<StackPanel Height="" Width="" HorizontalAlignment="Left">
<TextBox Name="txtBox1" Width="" HorizontalAlignment="Left"></TextBox>
<TextBox Name="txtBox2" Width="" Margin="0 10" HorizontalAlignment="Left"></TextBox>
<TextBox Name="txtBox3" Width="" Margin="0 10" HorizontalAlignment="Left"></TextBox>
</StackPanel>

要实现的需求就是通过Caculate方法实现第三个文本框是前两个之和,也就是我们需要将前两个文本框绑定到Add方法的两个参数,第三个绑定到返回值上。

然后我们在构造函数中编写后台代码

  ObjectDataProvider odp = new ObjectDataProvider();
//设置用于绑定源的对象
odp.ObjectInstance = new Caculate();
//设置调用方法的名称
odp.MethodName = "Add";
//添加方法参数
odp.MethodParameters.Add("");
odp.MethodParameters.Add("");
//绑定参数到txtBox1和txtBox2
this.txtBox1.SetBinding(TextBox.TextProperty, new Binding("MethodParameters[0]") { Source = odp, BindsDirectlyToSource = true, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged });
this.txtBox2.SetBinding(TextBox.TextProperty, new Binding("MethodParameters[1]") { Source = odp, BindsDirectlyToSource = true, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged });
//绑定结果
this.txtBox3.SetBinding(TextBox.TextProperty, new Binding(".") { Source = odp});

先来分析一下上面代码。ObjectDataProvider类的作用是包装一个以方法暴露数据的对象,这里就先创建一个ObjectDataProvider的对象.然后用一个Caculate对象做为ObjectInstance对象复制。这就是把Caculate对象包装在了ObjectDataProvider里面。接着使用MethodName属性指定调用的Caculate对象中Add的方法。问题来了,如果Caculator有多个构造器参数的方法Add应该如何区分?我们知道,重载方法的区别在于参数列表,紧接着两句就是向MethodParameter属性里面加入两个string类型的参数,这就相当于告诉ObjectDataProvider对象去调用Caculator对象中具有两个string类型参数的Add方法,换句话说,MethodParameter对于参数的感应是非常敏感的。

准备好数据源之后,我们准备创建Binding。前面我们已经讲过使用索引器作为Binding的Path,第一个Binding它的Source是一个ObjectDataProvider对象,Path是ObjectDataProvider中MethodParameters所引用的第一个元素。BindsDirectlyToSource这句话是告诉Binding只是将UI上的值传递给源而不是被ObjectDataProvider包装的Caculator,同时UpdateSourceTrigger设置为UI只要一有变化就更新Source。第二个Binding只是对第一个的翻版,只是把Path属性指向了第二个元素。第三个binding仍然使用ObjectDataProvider作为Source,但使用“.”作为Path----前面讲过,当数据源本身就是数据的时候就用“.”来做为Path,在XAML中"."可以不写。

注意:  在ObjectDataProvider对象作为Binding的Source的时候,这个对象本身就代表了数据,所以这里的Path使用的“.”,而不是Data属性。

6.使用RelativeSource当绑定源

当一个Binding有明确的来源的时候,我们可以通过Source或者ElementName赋值的办法让Binding与之关联。有些时候我们不能确定作为Source对象叫什么名字,但是我们知道它与做为Binding目标对象在UI上的相对关系,比如控件自己关联自己的某个数据,关联自己某级容器的数据,这时候就需要用到Binding的RelativeSource属性。

RelativeSource属性的类型是RelativeSource类,通过这个类的几个静态或者非静态的属性我们可以控制它搜索相对数据源的方式。

 <StackPanel x:Name="stackPanel1" Margin="">
<StackPanel x:Name="stackPanel2" Margin="">
<Grid Name="grid2">
<TextBox Name="txtBox1" Width="" Height="" HorizontalAlignment="Left"></TextBox>
</Grid>
</StackPanel>
</StackPanel>

我们看下上面结构   这个XAML结构为   StackPanel1----StackPanel2---Grid2---TextBox  。然后以相对路径来为TextBox进行绑定

RelativeSource relative = new RelativeSource(RelativeSourceMode.FindAncestor);
//设置要查找的上级级别
relative.AncestorLevel = ;
//设置要查找的类型
relative.AncestorType = typeof(StackPanel);
Binding binding = new Binding("Name")
{//设置相对绑定的数据源
RelativeSource = relative
};
this.txtBox1.SetBinding(TextBox.TextProperty, binding);

然后再观察以上代码。相对绑定源类为RelativeSource类,这个类构造可以放一个RelativeSourceMode枚举,这个枚举描述与绑定目标的位置相对的绑定源位置。枚举值有四个

  • PreviousData:当前显示向列表的上一个数据项
  • TemplateParent:引用应用了模板的元素,其中此模板中存在数据绑定元素。
  • Self:引用正在绑定的元素,允许你该元素的一个属性绑定到同一元素的其他属性上。  
  • FindAncestor:引用数据绑定元素的父链中的上级。 可用于绑定到特定类型的上级或其子类

在这里设置为了FindAncestor. 然后为RelativeSource设置查找的级别和查找的类型。这里是先筛选类型,再筛选级别,比如现在查找的是深度为1的StackPanel。所以选中的是StackPanel2 而不是Grid2 。最后将RelativeSource对象设置为Binding的数据源

  注意:设置数据源使用的是RelativeSource而不是Source

WPF Binding学习(四) 绑定各种数据源的更多相关文章

  1. WPF Binding学习&lpar;二&rpar;

    Binding作为数据的桥梁,连通业务逻辑层的对象(源对象)和UI的控件对象(目标对象).在这座桥梁上,我们不仅可以控制在源对象与目标对象是双向通行还是单向通行.还可以控制数据的放行时机,甚至可以在这 ...

  2. WPF Binding学习&lpar;三&rpar;

    转自;http://blog.csdn.net/lisenyang/article/details/18312199 1.控件与控件间的双向绑定 WPF还支持控件作为数据源, <TextBox ...

  3. WPF项目学习&period;四

    信息收录项目 版权声明:本文为博主初学经验,未经博主允许不得转载. 一.前言 记录在学习与制作WPF过程中遇到的解决方案.  需求文案.设计思路.简要数据库结构.简要流程图和明细代码,动图细化每步操作 ...

  4. WPF Binding(四种模式)

    在使用Binding类的时候有4中绑定模式可以选择 BindingMode TwoWay 导致对源属性或目标属性的更改可自动更新对方.此绑定类型适用于可编辑窗体或其他完全交互式 UI 方案. OneW ...

  5. WPF&plus;MVVM学习总结 DataGrid简单案例

    一.WPF概要 WPF(Windows Presentation Foundation)是微软推出的基于Windows 的用户界面框架,属于.NET Framework 3.0的一部分.它提供了统一的 ...

  6. WPF的Binding学习笔记&lpar;二&rpar;

    原文: http://www.cnblogs.com/pasoraku/archive/2012/10/25/2738428.htmlWPF的Binding学习笔记(二) 上次学了点点Binding的 ...

  7. WPF绑定各种数据源之object数据源

    一.WPF绑定各种数据源索引 WPF 绑定各种数据源之Datatable WPF绑定各种数据源之object数据源 WPF绑定各种数据源之xml数据源 WPF绑定各种数据源之元素控件属性 Bindin ...

  8. WPF绑定各种数据源之xml数据源

    一.WPF绑定各种数据源索引 WPF 绑定各种数据源之Datatable WPF绑定各种数据源之object数据源 WPF绑定各种数据源之xml数据源 WPF绑定各种数据源之元素控件属性 Bindin ...

  9. WPF Binding ElementName方式无效的解决方法--x&colon;Reference绑定

    原文:WPF Binding ElementName方式无效的解决方法--x:Reference绑定 需求: 背景:Grid的有一个TextBlock name:T1和一个ListBox,ListBo ...

随机推荐

  1. POJ 1528问题描述

    Description From the article Number Theory in the 1994 Microsoft Encarta: ``If a, b, c are integers ...

  2. 黑马程序员-集合(二)contains()方法的内部探索

    ------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 我们知道集合是用来存储对象的.在他们实现了众多的接口我们以Arraylist为列子 所有已实现的 ...

  3. Linux 创建swap分区

    --首先分出一个分区 /dev/sda5 (注意分区类型)mkswap /dev/sda5           --格式化分区成swap格式swapon /dev/sda5           --激 ...

  4. 关于三星手机照相机调用适配问题Android

    因为三星手机在照相的时候,会自动将自动转化为为横屏. 这里的话 就不讲具体怎么实现的,因为在网络上是有相关的代码. 主要的是在你拍完照返回的时候,先前的界面可能会重绘,所以会导致一些问题. 我暂时的办 ...

  5. 离职了,在家温故而知新----1 设计模式 &amp&semi; 开头

    工作四年有余,编写的代码都是业务代码.不涉及低层. 目前离职在家,过年完了,准备找工作了. 决定温故而知新,复习也是学习. 本着随遇而安的原则,随便从之前设计的众多条目中选择了一条开始复习. 设计模式 ...

  6. linux下fdisk分区管理、文件系统管理、挂载文件系统等

    分区管理工具有:fdisk, parted, sfdisk fdisk:对于一块硬盘来讲,最多只能管理15分区: # fdisk -l [-u] [device...]  查看硬盘设备分区信息 # f ...

  7. Vijos 1007 绕钉子的长绳子

    背景 平面上有N个圆柱形的大钉子,半径都为R,所有钉子组成一个凸多边形. 现在你要用一条绳子把这些钉子围起来,绳子直径忽略不计. 描述 求出绳子的长度 格式 输入格式 第1行两个数:整数N(1< ...

  8. Docker快速入门(二)

    上篇文章<Docker快速入门(一)>介绍了docker的基本概念和image的相关操作,本篇将进一步介绍image,容器和Dockerfile. 1 image文件 (1)Docker ...

  9. spring boot 常见的第三方集成

    spring boot基于1.x. 一 集成redis 1.1 配置 spring.redis.host = localhost spring.redis.port = 6379 spring.red ...

  10. Halcon示例:print&lowbar;quality 字符验证

    read_image (Image, 'fonts/arial_a1')get_image_size (Image, Width, Height)dev_close_window ()dev_open ...