Loading Data

Let's start with the data load lifecycle:

Silverlight RadDomainDataSource Data Load Lifecycle

Triggering a Load

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 is explained below.

Building The Query

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 (this is the 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. 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 we will call QDSCV from now on. 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:

  • Where

  • OrderBy

  • ThenBy

  • Skip

  • Take

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:

public QueryableDomainServiceCollectionView(DomainContext domainContext, EntityQuery<TEntity> entityQuery) 
     : base(domainContext, new DomainServiceCollection<TEntity>(domainContext)) 

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:

public EntityQuery<Customer> GetCustomersQuery() 
{ 
     this.ValidateMethod("GetCustomersQuery", null); 
     return base.CreateQuery<Customer>("GetCustomers", null, false, true); 
} 

So you can instantiate a new QDSCV like this:

NorthwindDomainContext context = new NorthwindDomainContext(); 
EntityQuery<Customer> query = context.GetCustomersQuery(); 
QueryableDomainServiceCollectionView<Customer> view = new QueryableDomainServiceCollectionView<Customer>(context, query); 

When you are using the RadDomainDataSource control, you only need to specify the domain context and the name of the query as a string.

<telerik:RadDomainDataSource 
   x:Name="customersDataSource" 
   QueryName="GetCustomers" PageSize="10" 
   LoadingData="OnCustomersDataSourceLoadingData" 
   LoadedData="OnCustomersDataSourceLoadedData"> 
   <telerik:RadDomainDataSource.DomainContext> 
       <e:NorthwindDomainContext /> 
   </telerik:RadDomainDataSource.DomainContext> 
</telerik:RadDomainDataSource> 

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.

Waiting for Data

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 binding:

<telerik:RadBusyIndicator IsBusy="{Binding IsBusy, ElementName=customersDataSource}"> 

Cancelling the Request

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:

public IQueryable<Customer> GetCustomers() 
{ 
   // Fake server slow-down. 
   Thread.Sleep(500); 
   return this.ObjectContext.Customers.OrderBy(c=>c.CustomerID); 
} 

Receiving Data

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.

AutoLoad

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 a property called LoadDelay which determines the delay between the time a change that prompts an automatic load occurs and the time the subsequent Load Link... is invoked.

In this article