您的位置:首页 > 其它

SilverLight商业应用程序开发---学习笔记(8) 适用于SilverLight商业应用程序的几个重要的类

2013-07-01 15:04 501 查看
尽管使用DomainDataSource控件很方便,但是使用该控件使得显示层与业务层呈紧耦合状态,因此在一般分层的应用开发中,很少直接使用DomainDataSource控件,而是选择集合视图作为显示层与数据层之间的桥梁,于是如下一些类就应运而生。这些类有两种,一种是完全在客户端执行逻辑,如LisCollectionView集合视图和PagedCollectionView集合视图,一种是完全在服务器端执行逻辑。在服务器端执行逻辑的好处是可以根据需要向客户端发送数据,从而减少了网络的流量。(比如DomainCollection的分页是在服务器端执行的,在网络传输的只是分页后指定页面的数据)。下面分别用实例给出各个类的用法。

在进行深入讨论之前,首先创建一个视图模型类并绑定到DataGrid控件上,后面的各系列操作都是在此视图模型类下展开的:

1)在SilverLight项目的View文件夹下创建一个视图:ProductListView.xaml;

2)在View文件夹下创建一个新类:ProductListViewModel.cs

usingSystem.Collections.Generic;
usingAdventureWorks.Web.Services;
usingAdventureWorks.Web.Models;

namespaceAdventureWorks.Views
{
publicclassProductListViewModel
{
publicIEnumerable<ProductSummary>Products{get;set;}

publicProductListViewModel()
{
ProductSummaryContextcontext=newProductSummaryContext();
varqry=context.GetProductSummaryListQuery();
varop=context.Load(qry);
Products=op.Entities;
}
}
}


3)在视图的构造器(后置代码)里创建视图模型类的实例并赋给视力瓣DataContext属性:

publicProductListView()
{
InitializeComponent();

this.DataContext=newProductListViewModel();
}


4)将视图中的控件绑定到视图模型上:

<sdk:DataGridItemsSource="{BindingProducts}"/>


1、ObservableCollection<T>泛型类

SIlverlight支持许多通用的泛型类,包括List,Dictionary,LinkedList,Stack和Queue。但是最重要的泛型类还是ObservableCollecton<T>泛型类,该类实现了INotifyCollectionChanged接口,暴露CollectionChanged事件,在向集合添加或从集合移除项目时会引发该事件。当ListBox,DataGrid,ComboBox控件的ItemsSource属性绑定到这种泛型类的实例以后,由于CollectionChanged事件的作用,集合变更时会自动更新控件里的相应项目。可以实现显示与业务逻辑分离,解除之间的紧耦合。

2、ListCollectionView/EnumerableCollectionView集合视图

ListCollectionView/EnumerableCollectionView集合视图可以在内存中(在客户端)筛选,排序和分组所承载的集合。(但这两个集合视图不支持数据分页)这两个集合视图不能直接实例化(因为其构造器为internal),需要CollectionViewSource类充当集合视图的“代理”,然后才能实例化。首先需要定义CollectionViewSource为资源,将一个集合赋值给其Source属性。这样该资源的View属性就可以作为ListCollectionView/EnumerableCollectionView集合视图使用,然后使用Filter,GroupDescriptions和SortDescriptions属性实现筛选,排序和分组功能。ListCollectionView/EnumerableCollectionView集合视图适用于如下情况:

已经将所有数据加载到客户端
需要将集合封装到集合视图以便在XAML中使用
不需要对UI的数据进行分页处理

3、PagedCollectionView集合视图

PagedCollectionView集合视图可以直接实例化,支持数据分页。该集合视图适合于如下场景:

已经将所有数据加载到客户端
需要在Viewmodel类中控制筛选、排序、分组和分页;
需要对UI的数据进行分页

实例:封装数据到PagedCollectionView,其实现步骤首先是在视图模型类里将集合封装为PagedCollectionView,然后将其作为视图模型暴露的属性以便进行绑定。

1)在项目中添加对System.Windows.Data.dll程序集的引用;

2)在ProductListViewModel类上添加对System.Windows.Data的引用;

3)向类中添加新的属性,类型为PagedCollectionView,命名为ProductCollectionView:

publicPagedCollectionViewProductCollectionView{get;set;}


4)在视图模型的构造函数里将集合封装为PagedCollectionView,将结果赋值给ProductCollectionView属性:

publicProductListViewModel()
{
ProductSummaryContextcontext=newProductSummaryContext();
varqry=context.GetProductSummaryListQuery();
varop=context.Load(qry);
Products=op.Entities;

ProductCollectionView=newPagedCollectionView(Products);
}


5)在ProductListView.xaml视图里,就不需要在构造函数里实例化视图模型类了,而是直接将控件绑定到视图模型的PagedCollectionView类型的属性ProductCollectionView上:

<sdk:DataGridItemsSource="{BindingProductCollectionView}"/>


实例二、使用PagedCollectionView进行筛选操作:需要给PagedCollectionView对象的Filter属性指定回调方法,Filter属性的返回值为bool类型的一个委托,当其值设为一个委托时,该委托会在回调中对源进行排序,其返回的Bool值就表示显示还是隐藏。每次筛选执行后就根据Filter的返回值确定是否调用Refresh方法。在下面的示例里,在视图模型类里创建了一个SearchText属性,用以绑定到UI的查询文本框中。当SearchText属性变更时,就执行筛选回调方法刷新PagedCollectionView对象,这样前端的显示就随之进行了更新:

1)添加SearchText属性,与自动属性不同之处是在每次设置后都要执行PagedCollectionView对象的Refresh方法:

privatestring_searchText="";
publicstringSearchText
{
get{return_searchText;}
set
{
_searchText=value;
ProductCollectionView.Refresh();
}
}


2)在视图模型的构造函数里,为ProductCollectionView集合视图指定筛选条件:

ProductCollectionView=newPagedCollectionView(Products);
ProductCollectionView.Filter=item=>
((ProductSummary)item).Name.IndexOf(SearchText,
StringComparison.InvariantCultureIgnoreCase)!=-1;

3)在视图里设置TextBox的绑定:

<TextBoxName="SearchTextBox"Grid.Column="1"Margin="0,3"
Text="{BindingSearchText,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>

有关PagedCollectionView的动态多条件选择,参考/article/5021422.html。

示例三:使用PagedCollectionView实现排序功能:需要实例化一个SortDescription对象,然后将该对象添加到PagedCollectionView的SortDescriptions集合属性即可:

1)在视图模型类中添加引用:

usingSystem.ComponentModel;

2)实例化SorDescription对象,并添加到SortDescriptions集合:

ProductCollectionView=newPagedCollectionView(Products);
SortDescriptionsortBy=newSortDescription("Name",ListSortDirection.Ascending);
ProductCollectionView.SortDescriptions.Add(sortBy);


示例四:使用PagedCollectionView实现分组功能:需要实例化一个PropertyGroupDescription对象,然后将该对象添加到PagedCollectionView的GroupDescriptions集合属性即可:

1)在视图模型类中添加引用:

usingSysetm.Windows.Data;

2)在实例化PagedCollectionView对象后,以下列代码用Model属性进行分组:

ProductCollectionView=newPagedCollectionView(Products);
PropertyGroupDescriptiongroupBy=newPropertyGroupDescription("Model");
ProductCollectionView.GroupDescriptions.Add(groupBy);



在分组操作中可以提供值转换器作为PropertyGroupDescription构造器的参数,用于分组;这在使用外键数据进行分组时特别有用。比如想要使用Category来分组Products,但是Products对象只包含Category的Id值,如果使用Id作分组,分组标识就成了Id值,这显然不是我们想要的。如果想要使用Category的名称来排遣序,就需要编写一个值转换器,将CategoryId转换为CategoryName。

示例五:使用PagedCollectionView实现分页:只需要将PagedCollectionView对象绑定到DataPager控件的Source属性即可:

<sdk:DataPagerPageSize="30"
Source="{BindingProductCollectionView}"/>


4、DomainDataSourceView集合视图

DomainDataSourceView集合视图由DomainDataSource通过其DataView属性暴露。无法通过代码创建该集合视图,只能通过DomainDataSource控件创建。DomainDataSourceView集合视图实现的筛选,排序,分页等功能是在服务器端完成的。

5、DomainCollectionView集合视图

DomainCollectionView集合视图由WCFRIAServiceToolKit引入,与DomainDataSource所表现的行为相同(通过RIA服务获取数据,在服务器端筛选,排序和分页数据),不同之处在于实现了视图与域上下文类的分离,这样视图无需要知道数据是如何获取的。需要引用Microsoft.Windows.Data.DomainServices.dll程序集。

使用DomainCollectionView集合视图需要三个关键组件:DomainCollectionView集合视图本身,需要封装的源集合以及“Loader(加载器)”,后者包括与服务器交互和更新源集合数据的类。DomainCollectionView充当了UI与加载器之间的桥梁。关系如图所示:





WCFRIAServicesToolkit已经实现了默认的加载器:DomainCollectionViewLoader,该加载器以方法委托作为构造器参数,当数据需要加载或加载完成时调用这些方法;

DomainCollectionView集合视图处理如下场景:

使用RIA服务从服务器中获取数据
使用MVVM设计模式

实例:从DomainCollectionView获取数据,步骤如下:

1)确保安装了WCFRIAServicesToolkit,并在SIlverlight项目中添加了Microsoft.Windows.Data.DomainServices.dll程序集的引用;

2)在ProductListViewModel类上添加如下引用:

usingSystem.ServiceModel.DomainServices.Client;

usingMicrosoft.Windows.Data.DomainServices;

3)在类中添加类型为DomainCollectionView的属性:ProductCollectionView:

publicDomainCollectionViewProductCollectionView{get;set;}

4)在视图模型类中添加如下代码,确保内存中的上下文实例唯一:

privateProductSummaryContext_context=newProductSummaryContext();

5)在视图模型类中添加如下两个方法:

privateLoadOperation<ProductSummary>LoadProductSummaryList()
{
EntityQuery<ProductSummary>query=_context.GetProductSummaryListQuery();
return_context.Load(query);
}

privatevoidOnLoadProductSummaryListCompleted(LoadOperation<ProductSummary>op)
{
if(op.HasError)
{
//NOTE:Youshouldaddsomelogicforhandlingerrorshere,andmark
//theerrorashandled.
//op.MarkErrorAsHandled();
}
elseif(!op.IsCanceled)
{
((EntityList<ProductSummary>)Products).Source=op.Entities;
}
}


6)在视图模型的构造器中添加如下代码:

publicProductListViewModel()
{
Products=newEntityList<ProductSummary>(_context.ProductSummaries);

varcollectionViewLoader=newDomainCollectionViewLoader<ProductSummary>(
LoadProductSummaryList,OnLoadProductSummaryListCompleted);

ProductCollectionView=
newDomainCollectionView<ProductSummary>(collectionViewLoader,Products);

ProductCollectionView.Refresh();

}


上述代码是创建DomainCollectionView的范式,注意加粗字体的内容以及各个方法传递的参数类型,特别传递的委托参数类型。

7)可以直接在视图中将ProductCollectionView属性绑定到控件的数据源属性:

<sdk:DataGridItemsSource="{BindingProductCollectionView}"/>


实例二:使用DomainCollectionView实现筛选:与PagedCollectionView对象类似,DomainCollectionView对象也有一个Filter属性,指定该属性一个实现了筛选逻辑的委托就可以实现筛选作业。但是这种筛选只对客户端的项目有效,如果要想在服务器端进行筛选操作,需要在DomainCollectionView的加载器里添加Where查询字句。实现方法如下:

1)与前述例子相类似,先在视图模型类中添加一个SearchBox属性以绑定到查询文本框中,并且在获得数据后刷新集合视图:

privatestring_searchText="";

publicstringSearchText
{
get{return_searchText;}
set
{
_searchText=value;
ProductCollectionView.Refresh();
}
}


2)在LoadProductSummary方法里添加Where条件字句以在服务器端筛选数据,注意对私有字段的访问:

privateLoadOperation<ProductSummary>LoadProductSummaryList()
{
EntityQuery<ProductSummary>query=_context.GetProductSummaryListQuery();
query=query.Where(x=>x.Name.Contains(_searchText));
return_context.Load(query);
}



3、绑定文本框到SearchText属性上:

<TextBoxName="SearchTextBox"Grid.Column="1"Margin="0,3"
Text="{BindingSearchText,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>


示例三:使用DomainCollectionView进行排序:与PagedCollectionView的配置方法类似,也是需要实例化一个SortDescription对象,然后将该对象添加到DomainCollectionView的SortDescriptions集合属性里:这些操作是在客户端完成的,如果想在服务器端实现排序也是可以的,另见分页部分的介绍;

1)添加如下引用:usingSystem.ComponentModel;

2)实现排序功能:

ProductCollectionView=
newDomainCollectionView<ProductSummary>(collectionViewLoader,Products);
SortDescriptionsortBy=newSortDescription("Name",ListSortDirection.Ascending);
ProductCollectionView.SortDescriptions.Add(sortBy);


示例四:使用DomainCollectionView实现分组功能:需要实例化一个PropertyGroupDescription对象,然后将该对象添加到DomainCollectionView的GroupDescriptions集合属性即可:

1)在视图模型类中添加引用:

usingSysetm.Windows.Data;

2)在实例化PagedCollectionView对象后,以下列代码用Model属性进行分组:

ProductCollectionView=
newDomainCollectionView<ProductSummary>(collectionViewLoader,Products);
PropertyGroupDescriptiongroupBy=newPropertyGroupDescription("Model");
ProductCollectionView.GroupDescriptions.Add(groupBy);


示例五:使用DomainCollectionView实现分页,好处是只向服务器请求所需要的数据,从而大幅度减少了网络流量;实现这一功能需要使用EntityQuery类的扩展方法:SortBy,PageBy以及SortAndPageBy。实现方法与步骤如下:

1)将DataPger控件的Source属性绑定到DomainCollectionView对象上:

<sdk:DataPagerPageSize="30"
Source="{BindingProductCollectionView}"/>


2)修改LoadProductSummaryList方法,确保在将查询传递到域下下文的Load方法之前,使用SortAndPageBy扩展方法将集合视图的状态调整为query:

privateLoadOperation<ProductSummary>LoadProductSummaryList()
{
EntityQuery<ProductSummary>query=_context.GetProductSummaryListQuery();
query=query.SortAndPageBy(ProductCollectionView);
return_context.Load(query);
}


3)为了完全实现分页行为,DataPager控件需要知道全部对象的数量。可以通过将查询对象的IncludeTotalCount属性为True来显示地通知服务器计算总记录数:

privateLoadOperation<ProductSummary>LoadProductSummaryList()
{
EntityQuery<ProductSummary>query=_context.GetProductSummaryListQuery();
query=query.SortAndPageBy(ProductCollectionView);
query.IncludeTotalCount=true;
return_context.Load(query);
}


4)获得服务器响应的同时,需要通过SetTotalItemCount将总记录数设置到DomainCollectionView对象上:

privatevoidOnLoadProductSummaryListCompleted(LoadOperation<ProductSummary>op)
{
if(op.HasError)
{
//NOTE:Youshouldaddsomelogicforhandlingerrorshere
op.MarkErrorAsHandled();
}
elseif(!op.IsCanceled)
{
((EntityList<ProductSummary>)Products).Source=op.Entities;

if(op.TotalEntityCount!=-1)
ProductCollectionView.SetTotalItemCount(op.TotalEntityCount);
}
}


5)确保在DomainCollectionView对象上设置了至少一个SortDescription,否则不同分页间导航会抛出异常;

6)将对Refresh方法的调用用如下代码替换:

using(ProductCollectionView.DeferRefresh())
{
ProductCollectionView.PageSize=30;//设置pagesize
ProductCollectionView.MoveToFirstPage();//设置当前页
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐