WPF Binding学习(四) 绑定各种数据源
2021-02-18 23:20
1.集合作为数据源
首先我们先创建一个模型类
public class Student { public int ID { get; set; } public String Name { get; set; } }
然后我们创建我们的页面布局
"300" Height="300" HorizontalAlignment="Left"> "listView1"> "编号" DisplayMemberBinding="{Binding ID}" Width="100"> "姓名" DisplayMemberBinding="{Binding Name}" Width="100">
在这里我们使用了ListView控件和GridView控件来显示数据,这两个控件从表面来看应该属于同一级别的控件。实际上并非如此!ListView是ListBox的派生类,而GridView是ViewBase的派生类,ListView中的View是一个ViewBase对象,所以,GridView可以做为ListView的View来使用而不能当作独立的控件来使用。这里使用理念是组合模式,即ListView由一个View,但是至于是GridVIew还是其它类型的View,由程序员自己选择。其次,GridView的内容属性是Columns,这个属性是GridViewColumnCollection类型对象。因为XAML支持对内容属性的简写,可以省略
接下来下后台代码
IListlist = new ObservableCollection () { new Student(){ID=1,Name="狗娃"}, new Student(){ID=2,Name="狗剩"}, new Student(){ID=3,Name="铁蛋"} }; this.listView1.ItemsSource = list;
只需在构造函数中创建对象并绑定到ListView上即可,然后运行就可以看到已经绑定完毕
接下来看一下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[0] = 1; dr[1] = "狗娃"; dt.Rows.Add(dr); dr = dt.NewRow(); dr[0] = 2; dr[1] = "狗剩"; dt.Rows.Add(dr); dr = dt.NewRow(); dr[0] = 1; dr[1] = "铁蛋"; 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文件
"1.0" encoding="utf-8" ?>"1"> 狗娃 "2"> 狗剩 "3"> 铁蛋
然后创建XAML
"300" Name="stackPanel1"> "listView1"> "编号" DisplayMemberBinding="{Binding XPath=@id}"> "姓名" DisplayMemberBinding="{Binding XPath=Name}">
注意: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
现在还还用刚开始创建的那个Student模型类和XAML代码,
public class Student { public int ID { get; set; } public String Name { get; set; } }
"300" Width="300" HorizontalAlignment="Left"> "listView1"> "编号" DisplayMemberBinding="{Binding ID}" Width="100"> "姓名" DisplayMemberBinding="{Binding Name}" Width="100">
我们只需更改数据源即可
Liststus = new List () { new Student(){ID=1,Name="狗娃"}, new Student(){ID=2,Name="铁蛋"}, new Student(){ID=3,Name="狗剩"} }; this.listView1.ItemsSource = from stu in stus where stu.Name.StartsWith("狗") select stu;
还可以将数据放在DataTable中
DataTable dt = CreateDt(); DataRow dr = dt.NewRow(); dr[0] = 1; dr[1] = "狗娃"; dt.Rows.Add(dr); dr = dt.NewRow(); dr[0] = 2; dr[1] = "狗剩"; dt.Rows.Add(dr); dr = dt.NewRow(); dr[0] = 1; dr[1] = "铁蛋"; dt.Rows.Add(dr); this.listView1.ItemsSource = from row in dt.Rows.Cast() 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 = 0; double y = 0; double z = 0; if (double.TryParse(arg1, out x) && double.TryParse(arg2, out y)) { z = x + y; return z.ToString(); } return "Iput Error"; } }
然后在XAML中创建三个TextBox框
"300" Width="300" HorizontalAlignment="Left"> "txtBox1" Width="120" HorizontalAlignment="Left"> "txtBox2" Width="120" Margin="0 10" HorizontalAlignment="Left"> "txtBox3" Width="120" Margin="0 10" HorizontalAlignment="Left">
要实现的需求就是通过Caculate方法实现第三个文本框是前两个之和,也就是我们需要将前两个文本框绑定到Add方法的两个参数,第三个绑定到返回值上。
然后我们在构造函数中编写后台代码
ObjectDataProvider odp = new ObjectDataProvider(); //设置用于绑定源的对象 odp.ObjectInstance = new Caculate(); //设置调用方法的名称 odp.MethodName = "Add"; //添加方法参数 odp.MethodParameters.Add("0"); odp.MethodParameters.Add("0"); //绑定参数到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属性。
文章标题:WPF Binding学习(四) 绑定各种数据源
文章链接:http://soscw.com/index.php/essay/57271.html