entitylist /domaincollectionview /domaincollectionviewloader is included in Microsoft. windows. data. add this DLL reference in the domainservices DLL to use these three items. These three things can be used to implement server-side filtering, paging, and sorting (in viewmodel, call the WCF Ria service to implement server-side paging, sorting, and filtering , instead of using the domain datasource mvvm unfriendly Control ):
- Entitylist <t> is an observablecollection backed by an entityset, its important to know that when an entity is removed from the list it also gets removed from associated entityset but it is not automatically added when a new entity is added to backed entityset.
- Domaincollectionview <t> is a icollectionview implementation, so it exposes everything you need to page/sort your data and accepts a collectionviewloader and a ienumerable <t> As constructor parameters.
- Domaincollectionviewloader <t> is a collectionviewloader implementation that accepts the method to invoke to load data and another method to invoke when load operation completes.
Background:
- Source code download: server-side filtering, paging, and sorting using the domaincollectionview
- Introducing an mvvm-friendly domaindatasource: The domaincollectionview
- Domaincollectionview updates for Mix '11
The final implementation (Filtering/searching/paging/sorting are all loaded on the server as needed):
Check whether the server page is displayed. Use Fiddler to check whether the current page number is returned:
Use Fiddler to check whether the HTTP request on the page is like this:
Use Fiddler to check whether the HTTP request for filtering/searching is like this:
Implementation Principle
Let's look at the source code implementation. The focus is that the domainservice of the WCF Ria service has a count function. As I mentioned above, the function to retrieve the total number of pages on this page cannot be saved on the server.
Using system; using system. collections. generic; using system. componentmodel. dataannotations; using system. LINQ; using system. servicemodel. domainservices. hosting; using system. servicemodel. domainservices. server; using system. threading; namespace domaincollectionviewsample. web {[enableclientaccess ()] public class sampledomainservice: domainservice {private const int uiwait = 1000; // overridden to support paging over poco entities. // If You're extending a derived domainservice // IMPLEMENTATION This is already done for you. protected override int count
(Iqueryable
Query) {return query. Count ();} public iqueryable
Getallentities () {return this. getentities (byte. maxvalue);} public iqueryable
Getentities (Byte Count) {This. waitalittle (); List
Entities = new list
(); For (byte I = 1; I <count; I ++) {entities. add (this. getentity (I);} return entities. asqueryable ();} public sampleentity getentity (byte key) {sampleentity entity = new sampleentity (); entity. key = key; entity. byte = key; entity. uint16 = key; entity. int32 = key; entity. single = key; entity. string = sampledomainservice. getentitystring (key); entity. guid = guid. parse ("00000000-0000-0000-0000-" + entity. string); Return entity;} private void waitalittle () {If (sampledomainservice. uiwait> 0) {thread. sleep (sampledomainservice. uiwait );}}///
/// Returns a unique string for the specified
./// ///
/// Returns a 12-character string of decending numbers. for instance, // "000000054321" is returned for 5 and "111098765432" is returned for // 11. ///
///
The key to get the string ///
A unique string
Private Static string getentitystring (byte key) {string STR = string. empty; while (Str. length <12) & (Key> 0) {STR + = key --;} while (Str. length <12) {STR = "0" + STR;} return Str. substring (0, 12) ;}} public class sampleentity {[Key] public int key {Get; set;} public byte {Get; set;} public uint16 uint16 {Get; set;} public int32 {Get; set;} public single {Get; set;} Public String string {Get; set;} public guid {Get; set ;}}}
The viewmodel section is used to bind the DataGrid and datapager to the domaincollectionview <t>. This view is loaded by domaincollectionviewloader <t>, and the sorting and paging operations are performed through entityquery <t>. this has some limitations.
Using system; using system. collections. generic; using system. collections. specialized; using system. componentmodel; using system. servicemodel. domainservices. client; using system. windows. input; using domaincollectionviewsample. web; using Microsoft. windows. data. domainservices; namespace domaincollectionviewsample {public class sampleviewmodel: inotifypropertychanged {private readonly sampledomaincontext _ context = new sampledomaincontext (); Private readonly domaincollectionview
_ View; private readonly domaincollectionviewloader
_ Loader; private readonly entitylist
_ Source; private readonly icommand _ searchcommand; private bool _ canload = true; private string _ searchtext = string. Empty; Public sampleviewmodel () {This. _ source = new entitylist
(This. _ context. sampleentities); this. _ loader = new domaincollectionviewloader
(This. loadsampleentities, this. onloadsampleentitiescompleted); this. _ view = new domaincollectionview
(This. _ loader, this. _ source); # region designerproperties. isindesigntool // swap out the loader for design-time scenarios if (designerproperties. isindesigntool) {designtimeloader loader = new designtimeloader (); this. _ view = new domaincollectionview
(Loader, loader. source) ;}# endregion this. _ searchcommand = new relaycommand (this. onsearch); // go back to the first page when the sorting changes inotifycollectionchanged policyingsortdescriptions = (inotifycollectionchanged) This. collectionview. sortdescriptions; policyingsortdescriptions. collectionchanged + = (sender, e) => This. _ view. movetofirstpage (); Using (this. collectionview. deferrefresh ()){ This. _ view. pagesize = 10; this. _ view. movetofirstpage () ;}# region View Properties public bool canload {get {return this. _ canload;} private set {If (this. _ canload! = Value) {This. _ canload = value; this. raisepropertychanged ("canload") ;}} public icollectionview collectionview {get {return this. _ view ;}} Public String searchtext {get {return this. _ searchtext;} set {If (this. _ searchtext! = Value) {This. _ searchtext = value; this. raisepropertychanged ("searchtext") ;}} public icommand searchcommand {get {return this. _ searchcommand ;}# endregion private loadoperation
Loadsampleentities () {This. canload = false; entityquery
Query = This. _ context. getallentitiesquery (); If (! String. isnullorwhitespace (this. searchtext) {query = query. where (E => E. string. contains (this. searchtext);} return this. _ context. load (query. sortandpageby (this. _ view);} private void onloadsampleentitiescompleted (loadoperation
OP) {This. canload = true; If (op. haserror) {// todo: handle errors op. markerrorashandled ();} else if (! Op. iscanceled) {This. _ source. Source = op. Entities; If (op. totalentitycount! =-1) {This. _ view. settotalitemcount (op. totalentitycount) ;}} private void onsearch () {// This makes sure we refresh even if we're already on the first page using (this. _ view. deferrefresh () {// This will lead us to re-query for the total count this. _ view. settotalitemcount (-1); this. _ view. movetofirstpage () ;}# region inotifypropertychanged public event propertychangedeventhandler propertycha Nged; protected virtual void onpropertychanged (propertychangedeventargs e) {propertychangedeventhandler handler = This. propertychanged; If (handler! = NULL) {handler (this, e) ;}} protected void raisepropertychanged (string propertyname) {This. onpropertychanged (New propertychangedeventargs (propertyname);} # endregion # region sample data private class designtimeloader: collectionviewloader {Private Static readonly ienumerable
Source = new [] {New sampleentity {guid = guid. newguid ()}, new sampleentity {guid = guid. newguid ()}, new sampleentity {guid = guid. newguid () },}; public ienumerable
Source {get {return designtimeloader. source ;}} public override bool canload {get {return true ;}} public override void load (Object userstate) {This. onloadcompleted (New asynccompletedeventargs (null, false, userstate) ;}# endregion # region relaycommand // This is just a light version I wrote for this sample. in most cases you'll // want to use the relaycommand type provided by an mvvm framework. private class relaycommand: icommand {private readonly Action _ Action; Public relaycommand (action Action) {This. _ Action = action;} public event eventhandler canexecutechanged; Public bool canexecute (object parameter) {return true;} public void execute (object parameter) {This. _ Action () ;}# endregion }}
Foreground XAMLCodeI will not explain it. It is very simple to bind it to viewmodel. In addition, the object bound to the DataGrid and datapager is domaincollectionview <t>.
Download all source code and run it directly. If it is referenced, check my article.Article.