您好,欢迎访问一九零五行业门户网

WPF数据绑定(2 绑定列表数据Binding to List Data)

(读完此系列wpf和silverlight的数据绑定问题你就轻松搞定 ) 1 binding to list data 前面都是绑定到一个对象,下面我们学习绑定到对象列表的方法。 我们还是先组织要绑定的数据,对象所对应的类还是person,但新增了一个新类people,该类用来组织person的列
(读完此系列wpf和silverlight的数据绑定问题你就轻松搞定)
1 binding to list data前面都是绑定到一个对象,下面我们学习绑定到对象列表的方法。
我们还是先组织要绑定的数据,对象所对应的类还是person,但新增了一个新类people,该类用来组织person的列表.代码如下:
using system; using system.collections.generic; using system.componentmodel;//inotifypropertychanged namespace simpledatabinding { class person : inotifypropertychanged { public event propertychangedeventhandler propertychanged; protected void notify(string propname) { if (this.propertychanged != null) { propertychanged(this, new propertychangedeventargs(propname)); } } public person() { _age = 0; _name = null; this.currentdate = datetime.now; } private string _name; public string name { get { return _name; } set { if (value == _name) { return; } _name = value;//注意:不能用this.name来赋值,如果这样形成循环调用,栈溢出 notify(name); } } private int _age; public int age { get { return _age; } set { if (value == _age) return; _age = value; notify(age); } } public datetime currentdate { get; set; } } //people类 class people : listperson> { } }
注意在同一命名空间下的代码最后添加了perople类。
我们在ui里显示的xaml如下:
window x:class=listdatabinding.bindlistdatatest xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml xmlns:src=clr-namespace:listdatabinding title=bindlistdatatest height=113 width=300> window.resources> src:people x:key=family> src:person name=jack age=18/> src:person name=tom age=30/> src:person name=jone age=14/> src:person name=rose age=17/> src:person name=mike age=13/> src:people> window.resources> grid datacontext={staticresource family}> grid.rowdefinitions> rowdefinition/> rowdefinition/> grid.rowdefinitions> grid.columndefinitions> columndefinition width=80/> columndefinition width=*/> grid.columndefinitions> textblock grid.row=0 grid.column=0 text=name textalignment=center verticalalignment=center/> textblock grid.row=1 grid.column=0 text=age textalignment=center verticalalignment=center/> textbox grid.row=0 grid.column=1 name=txtname text={binding path=name} /> textbox grid.row=1 grid.column=1 name=txtage text={binding path=age}/> grid> window>
我们发现这样的ui只能显示第一个数据项目,也就是说列表的当前项为0,至于其他的就无法显示出来了。
如果要显示其他的只有可通过如下代码的方式来取(注意:书中代码似乎有问题):
private void btnnext_click(object sender, routedeventargs e) { people people = (people)this.findresource(family); txtname.text = people[1].name; txtage.text = people[1].age.tostring(); }
1.1当前项current item取得当前项
可以通过上面的方法取得当前项,当然我们更专业的做法还是使用collection view
还是代码说明比较简洁:
people people = (people)this.findresource(family); icollectionview view = collectionviewsource.getdefaultview(people); person peron = (person)view.currentitem;
注意:icollectionview在system.componentmodel命名空间里。
导航当前项
还是代码来说明更合适点:
private icollectionview getview() { people people = (people)this.findresource(family); icollectionview view = collectionviewsource.getdefaultview(people); return view; } private void btnnext_click(object sender, routedeventargs e) { icollectionview view = getview(); view.movecurrenttonext(); if (view.iscurrentafterlast) { view.movecurrenttolast(); } } private void btnprior_click(object sender, routedeventargs e) { icollectionview view = getview(); view.movecurrenttoprevious(); if (view.iscurrentbeforefirst) { view.movecurrenttofirst(); } }
1.2 list data targets我们将列表数据绑定到类似textbox这样的控件难以很好地展现列表数据。我们考虑listbox控件来列举多个数据信息。
这时的效果如下:列表确实显示了所有对象的信息,因为我们没有设置path属性,所以采用默认的convertation来处理,显示对象类型。同时一定要注意使用issynchronizatizedwithcurrentitem=true,这样才能列表信息与其他信息同步。但究竟如何才能更好地表达我们需要的信息呢,请参看下一节:
1.3 display members, value members, and look-up bindings代码示例也许更易理解:
listbox grid.row=3 grid.column=1 name=lstbox itemssource={binding} displaymemberpath=name selectedvaluepath=age issynchronizedwithcurrentitem=true/> button grid.row=4 grid.column=0 name=btnshowvalue content=showvalue click=btnshowvalue_click />
private void btnshowvalue_click(object sender, routedeventargs e) { messagebox.show(lstbox.selectedvalue.tostring()); }
1.4数据模板data templates这是利用listbox控件有一个itemtemplate属性下面,他可以接受一个datatemplate类实例,
该模板可以重复绑定到listbox的每一个项目元素,注意datatemplate只能指定一个孩子节点,所以一般使用容器控件来组织下面的布局。
listbox grid.row=3 grid.column=1 name=lstbox itemssource={binding}> listbox.itemtemplate> datatemplate> textblock text={binding path=name}> 的年龄是textblock text={binding path=age}>textblock> textblock> datatemplate> listbox.itemtemplate> listbox>
我本人不赞同书中这样的做法,添加一个stackpanel更舒服点。
1.5 列表改变list changes当我们改变列表的数据的时候,却出现如下现象:
只是因为我们需要绑定的列表需要实现inotifycollectionchanged接口:
namespace system.collections.specialized { public interface inotifycollectionchanged { event notifycollectionchangedeventhandler collectionchanged; } }
namespace system.collections.objectmodel { public class observablecollection : collection, inotifycollectionchanged, inotifypropertychanged { ... } }
欢呼雀跃吧,我们改变上面例题的代码,一切如我们想象的美好。
所有的一切就如此简单,简单代码改动:
//people类 class people : observablecollectionperson> { }
1.6 排序sorting简单的代码还是足以繁杂的文字,让我们看如下方法:
private void btnsort_click(object sender, routedeventargs e) { icollectionview view = getview(); if (view.sortdescriptions.count == 0) { view.sortdescriptions.add(new sortdescription(name, listsortdirection.ascending)); view.sortdescriptions.add(new sortdescription(age, listsortdirection.descending)); } else { view.sortdescriptions.clear(); } }
当然我们还可以自定义排序方式:
class personsorter:icomparer { public int compare(object x, object y) { person lhs = (person)x; person rhs = (person)y; // sort name ascending and age descending int namecompare = lhs.name.compareto(rhs.name); if (namecompare != 0) return namecompare; return rhs.age - lhs.age; } }
注意:wpf不使用system.collection.generic命名空间的泛型icomparer接口,而是使用system.collection的。呵呵。
使用代码如下:
private void btnsort_click(object sender, routedeventargs e) { listcollectionview view = (listcollectionview)getview(); if (view.customsort == null) { view.customsort = new personsorter(); } else { view.customsort = null; } }
注意:listcollectionview支持自定义和排序,其他的不支持。
1.7 集合缺省视图类型default collection view
1.8 过滤 filter依然是我熟悉的表达方式:代码:
private void btnfilter_click(object sender, routedeventargs e) { listcollectionview view = (listcollectionview)getview(); if (view.filter == null) { view.filter = delegate(object item) { return ((person)item).age > 17; }; } else { view.filter = null; } }
1.9 分组grouping分组的意思大家很明白就是按照某一个或几个关键属性进行分类。
进行分组很简单和sort类似,只需要以下几行代码:
icollectionview view = getview(); if (view.groupdescriptions.count == 0) { view.groupdescriptions.add(new propertygroupdescription(age)); } else { view.groupdescriptions.clear(); }
但这在ui层面并没有任何影响,这需要我们对itemscontrol类的控件(例如listbox)设置groupstyle属性,groupstyle类缺省地提供了一个静态的属性实现,我们可以如下设置:
listbox grid.row=3 grid.column=1 name=lstbox itemssource={binding} issynchronizedwithcurrentitem=true> listbox.groupstyle> x:static member=groupstyle.default/> listbox.groupstyle> listbox.itemtemplate> datatemplate> textblock text={binding path=name}> 的年龄是textblock text={binding path=age}>textblock> textblock> datatemplate> listbox.itemtemplate> listbox>
但也许这并不是我们所喜欢的界面,简单得让人生厌,还好微软提供了这个对象的一个属性:headertemplate用于定义分组的栏目的外观,微软总是为大家想得那么周到,养活那么多天才是需要钱的,希望大家不要老是讲微软的坏话。
listbox.groupstyle> groupstyle> groupstyle.headertemplate> datatemplate> stackpanel background=green orientation=horizontal> textblock text={binding name}/> textblock text=(/> textblock text={binding itemcount}/> textblock text=)/> stackpanel> datatemplate> groupstyle.headertemplate> groupstyle> listbox.groupstyle>
有这模板属性一切由你发挥,真是好也,然而即使这样解决了ui问题,但是如果我们还希望更进一步,能否实现范围内分组呢?呵呵,然也:
这时我们不需要去想着如何继承groupstyle类,而是采用围魏救赵的方式,定义一个ivalueconverter,
public class agerangeconvert : ivalueconverter { public object convert(object value, type targettype, object parameter, cultureinfo culture) { int _value = (int)value; if (_value return 10岁以下; else if (_value return 20岁以下; else return 20岁以上; } public object convertback(object value, type targettype, object parameter, cultureinfo culture) { throw new notimplementedexception(); } }
简单调整前面分组代码:
icollectionview view = getview(); if (view.groupdescriptions.count == 0) { view.groupdescriptions.add(new propertygroupdescription(age,new agerangeconvert())); } else { view.groupdescriptions.clear(); }
一切搞定,享受成果吧:
既然groupdescripions是个集合类型,我们不妨看下面代码究竟是什么效果:
icollectionview view = getview(); if (view.groupdescriptions.count == 0) { view.groupdescriptions.add(new propertygroupdescription(age,new agerangeconvert())); view.groupdescriptions.add(new propertygroupdescription(age)); } else { view.groupdescriptions.clear(); }
运行如下:
呵呵,这不正是有时你需要的效果吗?至于界面如何优化,模板如何定义更好看我们以后话题再
其它类似信息

推荐信息