will continue the series of blog posts about RadDomainDataSource with the most important one – the one about loading data. If you are not familiar with RadDomainDataSource then you should go back and read my introductory blog post.
Let us move straight to the data load lifecycle.
A load operation can be triggered in two ways. You can either call the Load method explicitly or you can rely on the AutoLoad functionality, which I will explain later in this post.
After a load has been requested a query based on user input is constructed on the client. This query tells the server things such as “Give me the first page of (paging) all sales employees (filtering) ordered by their sick leave hours (sorting). RadDomainDataSource will build this query based on its FilterDescriptors, SortDescriptors, PageSize and PageIndex.
If you have a Telerik control such as RadGridView, RadDataFilter, or RadDataPager that is bound to RadDomainDataSource then you don’t have to do anything since the descriptors and paging of RadDomainDataSource will be automatically updated. For example, when the user sorts RadGridView, RadGridView will “talk” to RadDomainDataSource and add a SortDescriptor to it. In fact, when two Telerik data controls detect each other they start synchronizing their descriptors automatically. They recognize each other thanks to the IQueryableCollectionView interface, but this is a topic for a separate blog post. You can use RadDomainDataSource with any other control, but it would then be your responsibility to maintain its descriptors.
To be completely correct, it is not RadDomainDataSource that builds the query, but its inner view -- the QueryableDomainServiceCollectionView, which I will call QDSCV from now on since I hate typing its name and I don’t have JustCode in Windows Live Writer. Since RadDomainDataSource is just a XAML-friendly thin wrapper over the QDSCV it simply delegates all the work to the view.
The query that is sent to server is of type EntityQuery. MSDN tells us that this class represents a query method invocation. In your client application, you can apply additional filtering on a query to limit which entities are returned. You use LINQ and a subset of LINQ query operators to modify the results returned from the query. The following lists the available query operators:
After you apply additional filtering, you pass the EntityQuery object as a parameter in the Load method of the DomainContext to execute the query and get the results.
That is exactly what the QDSCV does. It takes the original entity query, does some LINQ Expression magic to append the sorting, filtering, and paging information, and then calls the Load method of its DomainContext.
If you are doing MVVM and you are working directly with the QDSCV (i.e. you don’t have a RadDomainDataSource control), you will notice that the constructor of this class requires two things:
The DomainContext is automatically generated for you by Visual Studio each time you build the server-side project. If the DomainService has a method called GetCustomers, then your DomainContext will have a method called GetCustomersQuery with the following signature:
So you can instantiate a new QDSCV like this:
If you are using the RadDomainDataSource control, you only need to specify the domain context and the name of the query as a string.
The control will then find the appropriate method on the DomainContext by using reflection. After that it will instantiate its inner QDSCV in the same manner.
Once the query has been prepared by the QDSCV, it is time to call the Load method of the DomainContext. Before doing that however, the LoadingData event is fired. In the event handler you have a last chance to modify the EntityQuery by hand, change the LoadBehavior or cancel the whole operation altogether. If you don’t cancel the load, you exit the event handler and execution transfers to the UI thread. This is where we start waiting for the server to send some data back.
The UI thread will not block and will continue executing normally since loading data is an asynchronous process. Several properties of RadDomainDataSource (QDSCV respectively) will change to indicate that something is going on. The IsLoadingData property will evaluate to true while we are waiting for the server to return the data. Same applies for the IsBusy property. You might wonder why we have both of them. IsLoadingData is true while we are loading data, whereas IsBusy is true while we are either loading data or submitting changes. As you might have already guessed, there is a third property called IsSubmittingData. The IsBusy property is perfect for busy indicator bindings:
While you are waiting for data to return you can always call the CancelLoad method or execute the CancelLoadCommand. This will cancel the current load request. In order to test this functionality, you might want to increase the fake server delay I have placed in NorthwindDomainService:
Once the server returns the data, the QDSCV will detect this and update itself with the new entities. You don’t have to do anything special here. If you have bound your ItemsControl (for example RadGridView) to a QDSCV or RadDomainDataSource.DataView it will be automatically refreshed. This is the moment when the LoadedData event will be fired. If there was some kind of server error it will be stored in the event arguments so you can take the appropriate action.
RadDomainDataSource has a property called AutoLoad. If AutoLoad is true, a load request is made each time something that affects the query changes. The changes that will trigger an auto-load include changes in the FilterDescriptors, SortDescriptors, GroupDescriptors, and QueryParameters. Furthermore, data is automatically reloaded when the PageIndex or PageSize change. Changing the page index will always load the new page of data regardless of the AutoLoad setting.
When AutoLoad is false, it is your responsibility to request a load, for example on a button click. This can be done either through the Load method or by using the LoadCommand if you are a MVVM person. Additionally, there is something called LoadDelay, but I will talk about it in one of my next blog posts.
As always, I have attached a sample project that contains all of the things that I talked about. The best way to learn what is going on under the hood would be to place breakpoints in all the methods on the client and the server and examine the local variables with the debugger.
If you have a specific question about how something works or if I couldn’t explain a concept very well – don’t hesitate to ask.
Download Sample Project