Set in wcf ria Services (2)

Source: Internet
Author: User

This is the second part of this article.

In the first part, we discuss two relatively simple set types: EntitySet and EntityList. In this article, we will learn more about the other two more advanced types: ICollectionView and DomainCollectionView.

 

ICollectionView

ICollectionView is not a new interface. It has been implemented by a large number of Silverlight controls, such as DataGrid. Now we can use it directly in ViewModel. To allow controls to be bound to an ICollectionView implementation (for example, the familiar CollectionViewSource and PagedCollectionView), we can do this:

 

Private ICollectionView CreateView (IEnumerable source ){
CollectionViewSource cvs = new CollectionViewSource ();
Cvs. Source = source;
Return cvs. View;
}

Private ICollectionView _ books;
Public ICollectionView Books {
Get {
If (this. _ books = null ){
This. _ books = CreateView (this. Context. Books );
This. _ books. Filter = new Predicate <object> (BookCorrespondsToFilter );
}
Return this. _ books;
}
}
When the Book data is loaded, it is automatically reflected in the View:

Public CollectionViewViewModel (){
InstantiateCommands ();

// Load books
Context. Load <Book> (Context. GetBooksQuery (). Take (10 ));
}
 

ICollectionView: add and remove data

You can directly add and remove entities from the Context. changes to these entitysets will be tracked by CollectionViewSource.

So what does this mean? So far, we have not seen the difference between this method and the direct use of EntitySet, right? In fact, what really special about ICollectionView is that you can add filtering, sorting, and grouping rules.

ICollectionView Filtering

ICollectionView defines a Filter attribute of the Predicate <object> type. Let's add and modify our code:

Private ICollectionView _ books;
Public ICollectionView Books {
Get {
If (this. _ books = null ){
This. _ books = CreateView (this. Context. Books );
This. _ books. Filter = new Predicate <object> (BookCorrespondsToFilter );
}
Return this. _ books;
}
}

Public bool BookCorrespondsToFilter (object obj ){
Book book = obj as Book;

If (filterActive ){
Return book. Title. Contains ("Silverlight ");
}

Return true;
}
When the BookCorrespondsToFilter method is executed, it checks whether the Title attribute of each Book contains the word "Silverlight". If it does not contain the word, it is not displayed in the View.

The function provided by the current code is only used when you clearly know the filtering time. However, most applications require users to determine the filtering time. Then, let's make some changes: add the filterActive attribute. When you click Add Filter, it is set to true.

Public bool BookCorrespondsToFilter (object obj ){
Book book = obj as Book;

If (filterActive ){
Return book. Title. Contains ("Silverlight ");
}

Return true;
}
When we click the button, we will find that the interface has not changed. Why?

When we change the filtering condition or the Book object changes (such as changing its name), the ICollectionView will not automatically perform the filter again: the Filter method is executed only when the object is added to EntitySet. This means you have to explicitly notify it to use the new filter condition to re-check the loaded object. We can achieve this by calling the Refresh () method of ICollection:

Refresh = new RelayCommand () => {
Books. Refresh ();
});
Now, the View is re-created, and all Book objects are re-filtered. Of course, this is only necessary when we change the filter condition or the EntitySet changes.

 

ICollectionView sorting and grouping

ICollectionView has two interesting attributes: SortDescriptions and GroupDescription. You can use them to define the sorting and grouping rules for EntitySet.

The sorting operation can be performed by clicking the DataGrid column header bound to the ICollectionView, however, when we use other controls such as ListBox that have no headers, we need to change their sorting rules by code:

AddSort = new RelayCommand () => {
Books. SortDescriptions. Add (new SortDescription ("Title", ListSortDirection. Ascending ));
});
Grouping A set is similar:

AddGrouping = new RelayCommand () => {
Books. GroupDescriptions. Add (new PropertyGroupDescription ("Author "));
});
Effect

 

One thing to note is that once a set is grouped, UI virtualization will be disabled-so be cautious when operating a large amount of data. When grouping a large amount of data, it is generally necessary to work with paging.

ICollection is a good choice for sorting, filtering, and grouping. However, it can only act on data in the memory, which means that all data must be loaded to the client. This is suitable for most application scenarios. In other cases, we can solve the problem through DomainCollectionView.

 

DomainCollectionView

In many enterprise applications, tens of thousands or even millions of data records are sorted, filtered, and grouped. ICollectionView is no longer applicable to such scenarios. The reason is described above. We need a set that allows the server to sort, filter, group, and more important paging operations.

This is the responsibility of DomainCollectionView. You can find it in the Microsoft. Windows. Data. DomainServices program in the wcf ria Services Toolkit (this Assembly is already included in the sample code ). Using DomainCollectionView requires more settings than other sets, but once you have mastered these settings, you will find that they are still very simple. The Source and Loader (CollectionViewLoader by default) attributes are required during DomainCollection initialization.

Public DomainCollectionView <Book> Books
{
Get {
Return this. view;
}
}
Source defines the Source entity used for View (any set that implements IEnumerable). A typical example is the set that implements INotifyCollectionChanged.

This. source = new EntityList <Book> (Context. Books );
Loader focuses on data loading. When we use the default CollectionViewLoader, our colleagues need to input two callbacks: OnLoad and OnLoadCompleted, they define the events that occur when the data must be loaded and loaded. (You can also use a simple LoadOperation instead of CollectionViewLoader if you want ).

This. loader = new DomainCollectionViewLoader <Book> (
This. OnLoadBooks,
This. OnLoadBooksCompleted );
Private LoadOperation <Book> OnLoadBooks ()
{
Return this. Context. Load (this. query. SortPageAndCount (this. view ));
}

Private void OnLoadBooksCompleted (LoadOperation <Book> op)
{
If (op. HasError)
{
Op. MarkErrorAsHandled ();
}
Else if (! Op. IsCanceled)
{
This. source. Source = op. Entities;
If (op. TotalEntityCount! =-1)
{
This. Books. SetTotalItemCount (op. TotalEntityCount );
}
}
}
As you can see, in OnLoadeBooks, we confirm that the request execution contains SortDescription and paging (only the data required for the current page is loaded) and the total number of data (required by DataPager ).

When Books is loaded, the Source set is set to the loaded Book object, and the total number of objects is assigned to the TotalItemCount attribute through TotalEntityCount.

This. view = new DomainCollectionView <Book> (loader, source );
The rest is used for initialization of loading (for example, setting the page size to 5 ):

Using (this. view. DeferRefresh ())
{
This. view. PageSize = 5;
This. view. MoveToFirstPage ();
}
(If DeferRefresh () is used, the refresh data event of the view can be postponed until all the code segments included in the using are executed)

In fact, when we perform paging, sorting (and other operations that may start to refresh the View), the Loader is executed and loaded with data. Once the load operation is complete, the Source attribute will be updated and the View will be notified of the update and respond to changes through the notification mechanism.

(Note: In the release L version of the wcf ria Services Toolkit, SortPageAndCount has been changed to SortAndPageBy)

 

DomainCollectionView: add and remove data

The Code is as follows:

 

AddBook = new RelayCommand () =>
{
// You can add books like this, but DCV is server side oriented: to get correct
// Behaviour, you shocould add it to the Context and submit the changes, after which
// The next query will fetch the book you just added.
Book book = Books. AddNew () as Book;
Book. Author = "Kevin Dockx ";
Book. ASIN = "123456 ";
Book. Title = "Silverlight for dummies ";
});

DeleteBook = new RelayCommand () =>
{
// Deleting an item can be done like this, but shocould be done directly on the context
// & Submitted to the server
Books. RemoveAt (0 );
});
Then, this operation will lead to non-synchronization of View filtering, sorting, and other rules. After all, DomainCollectionView is designed to work on the server.

The correct way to add and remove objects is to perform corresponding operations on the server at the same time, such as adding an object to the Context (or removing it from the Context ), call SubmitChanges to submit it to the server and refresh your DomainCollectionView.


DomainCollectionView: data filtering, sorting, and grouping

Next, let's take a look at how to filter data. Simply add the corresponding Where condition after EntityQuery, for example:

AddFilter = new RelayCommand () =>
{
// Filters in DCV shocould be done by adding a Where clause to the query, as DCV is mainly used
// Server side logic

This. query = Context. GetOrderedBooksQuery (). Where (B => B. Title. Contains ("Silverlight "));
This. view. MoveToFirstPage ();

});
Next is sorting and grouping. When we click the column header, sortdesparts will be added to the Book collection to determine the next data read sorting policy and automatically retrieve data again.

Some applications require that the List jump to the first page after the sorting rule changes. For such a requirement, we need to write an event handler like this:

INotifyCollectionChanged policyingsortdescriptions = (INotifyCollectionChanged) this. Books. SortDescriptions;

Policyingsortdescriptions. CollectionChanged + = (sender, e) => {
This. view. MoveToFirstPage ();
};
Like using ICollectionView, we can also add custom SortDescription to DomainCollectionView using code.

AddSort = new RelayCommand () => {
Books. SortDescriptions. Add (new SortDescription ("Title", ListSortDirection. Ascending ));
Books. Refresh ();
});
The grouping method is similar:

AddGrouping = new RelayCommand () => {
Books. GroupDescriptions. Add (new PropertyGroupDescription ("Author "));
Books. Refresh ();
});
After integrating the above content, we finally get a set of server paging, sorting, and grouping:

 

Summary

Wcf ria Services SP1 adds or enhances many Collection types. Both better binding options and server-side paging and sorting sets make it easier to interact with MVVM. If you are using wcf ria Services in combination with MVVM to develop industry software or commercial programs, it is necessary to understand these new collection types.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.