开发者

Implementing Telerik VirtualQueryableCollectionView with MVVM pattern

I have an application that was implemented using the Telerik RadGridView control and Caliburn.Micro MVVM framework. Because of some performance problems, I needed to implement the Telerik VirtualQueryableCollectionView in place of the direct control-to-ObservableCollection binding that was being used. The original code has the ItemsSouce property of the RadGridView was bound to the Prices property of the view model. I had to eliminate that binding and this in the code-behind:

public PricingView(PricingViewModel vm)
{
    InitializeComponent();

    var dataView = new VirtualQueryableCollectionView()
                         { LoadSize=20, VirtualItemCount = vm.Prices.Count };
    dataView.ItemsLoading += (sender, e) =>
        {
            var view = sender as VirtualQueryableCol开发者_运维知识库lectionView;
            if (dataView != null)
            {
                view.Load(e.StartIndex, vm.Prices.Skip(e.StartIndex).Take(e.ItemCount));
            }
        };
    this.PricesGridView.ItemsSource = dataView;
}

Since this code only deals with UI specific functionality and it is specific the the view implementation, I am comfortable that this code belongs in the code-behind rather than the ViewModel as it would be a departure from ther MVVM pattern to put a reference to VirtualQueryableCollectionView in the ViewModel. The part that I am not happy with is passing the reference to the ViewModel into the constructor of the View. Is there a good way to get the reference in the code-behind without having to pass the reference in the constructor?

Or is there a better way to do all of this?


My application is implemented with MVVM Light, in my case I used the VirtualQueryableCollectionView class in the ViewModel instead the View.

I did so because I think this class is very similar to the ObservableCollection although it is not part of the core classes. Actually, VirtualQueryableCollectionView is not limited to the Telerik controls but many other standard controls like the ListView.

The fetch is in my case implemented in the Model.

void MainViewModel()
{
    this.Traces = new VirtualQueryableCollectionView<MyEntityClass>()
    {
        // ViewModel also manages the LoadSize
        LoadSize = this.PageSize,
        VirtualItemCount = myModel.TotalCount
    };
    this.Traces.ItemsLoading += (s, args) =>
    {
        this.Traces.Load(args.StartIndex, 
                         myModel.FetchRange(args.StartIndex, args.ItemCount));
    };
}


Not sure what "performance problems" means, but I'm going to assume that means that when you fill the collection from the UI thread it blocks the application long enough it appears unresponsive.

There are two common solutions for this. First is to simply fill your collection from a background thread.

The naive implementation is to simply push the loading onto a ThreadPool thread, then use the Dispatcher to marshall the calls to add items to the ObservableCollection onto the UI thread.

A nicer approach (one that doesn't involve the ViewModel at all) is to use asynchronous bindings. You configure the fallback to some value that indicates to the user you are loading. Sometimes (depending on the situation) you can use a PriorityBinding to gradually fill your UI.

Other alternatives are to load and cache your data beforehand while displaying a splash screen. They're a bit different in WPF, it isn't like the old "display this form for a bit while I do work, then show the main form" mode of winforms. And, of course, there is always the classic data pagination. Its tough to code, but effective. Actually, I should say its tough in the UI. Its easy now in code (database.Skip(pageNumber * pageSize).Take(pageSize)).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜