This is a migrated thread and some comments may be shown as answers.

VirtualDataCollectionOnItemsLoading is called several times?

10 Answers 87 Views
DataBoundListBox
This is a migrated thread and some comments may be shown as answers.
This question is locked. New answers and comments are not allowed.
Vitalii
Top achievements
Rank 2
Vitalii asked on 19 Aug 2013, 11:57 PM
I have a bit specific scenario: i don't know size of the page before parsing server's answer. Also, i want to keep everything flexible enough (no special code for first call).
 So, my function is looking like this (viewmodel): 
public MyViewModel(IProductSubSubCategoriesDataService dataService)
        {
            _dataService = dataService;
 
            SelectedIndex = String.Empty;
            VirtualDataCollection = new VirtualizingDataCollection(1, Constants.PAGE_SIZE_PRODUCT_SUB_SUB_CATEGORY); // 30 for now
        }
}
 
private void VirtualDataCollectionOnItemsLoading(object sender, VirtualizingDataCollectionItemsLoadingEventArgs e)
        {
            if (String.IsNullOrEmpty(SelectedIndex)) return;
 
            ThreadPool.QueueUserWorkItem(async o =>
                {
                    var answerCached = await _dataService.ReadFromCacheAsync(SelectedIndex, e.StartIndex, e.Count);
                    if (answerCached.Status == AnswerDataServiceStatus.Ok)
                    {
                        DispatcherHelper.CheckBeginInvokeOnUI(() =>
                            {
                                lock (locker)
                                {
                                    VirtualDataCollection.ItemsLoading -= VirtualDataCollectionOnItemsLoading;
                                    VirtualDataCollection.Count = answerCached.TotalItems;
                                    VirtualDataCollection.LoadItems(e.StartIndex, answerCached.Collection);
                                    VirtualDataCollection.ItemsLoading += VirtualDataCollectionOnItemsLoading;
 
                                    IsBusy = false;
                                    Status = String.Empty;
                                }
                            });
 
                    }
                    else
                    {
                        var answer = await _dataService.RequestServerAsync(SelectedIndex, e.StartIndex, e.Count);
                        if (answer.Status == AnswerDataServiceStatus.Ok) // && answer.Collection.SequenceEqual(VirtualDataCollection.))
                        {
                            DispatcherHelper.CheckBeginInvokeOnUI(() =>
                                {
                                    lock (locker)
                                    {
                                        VirtualDataCollection.ItemsLoading -= VirtualDataCollectionOnItemsLoading;
                                        VirtualDataCollection.Count = answer.TotalItems;
                                        VirtualDataCollection.LoadItems(e.StartIndex, answer.Collection);
                                        VirtualDataCollection.ItemsLoading += VirtualDataCollectionOnItemsLoading;
 
                                        IsBusy = false;
                                        Status = String.Empty;
                                    }
                                });
                        }
                        else
                        {
                            if (String.Equals(Status, MainResources.Loading_process))
                                DispatcherHelper.CheckBeginInvokeOnUI(() => Status = MainResources.No_network_available);
                        }
                    }
                });
        }
 
public void OnNavigatedTo()
        {
            //ItemsList = null;
            Status = MainResources.Loading_process;
            VirtualDataCollection.ItemsLoading += VirtualDataCollectionOnItemsLoading;
 
            VirtualDataCollection.Count = 1;
}
 
public void OnNavigatedFrom()
        {
            SelectedIndex = String.Empty;
 
            VirtualDataCollection.ItemsLoading -= VirtualDataCollectionOnItemsLoading;
            VirtualDataCollection.Clear();
 
            Cleanup();
}

One of the problems that i faced was that first VirtualDataCollectionOnItemsLoading() is called at the page construction time. But i'm getting actual SelectedIndex (just product category index) only in the OnNavigatedTo().
Solution is quite simple: no subscription by default, unsubscribe while navigatingFrom, subscribe while navigatingTo the page again.

Now i'm getting another problem: _dataService.ReadFromCacheAsync() is called 2 times in a row, just one after another. And that produces quite notable delay, i see empty page for about 2 seconds.
First callstack is quite okay: http://clip2net.com/s/5AYleg , but the second one is quite weird: http://clip2net.com/s/5AYjqc

The most mysterious part for me - is that this appears only when i'm starting to read from cache. If i'm doing internet request, no second calls.


Maybe i'm wrong at some point, so here is just raw information: when i'm loading page for the first time (no cache), everything is smooth and nice: i see animation while waiting for server answer, page is responsible, etc.But when i'm visiting the page second time, i expect to see cached results instantly. Instead, i see a non-responsible blank page for about 2 seconds (shit, its even longer than waiting for servers answer). 
Any ideas?

10 Answers, 1 is accepted

Sort by
0
Vitalii
Top achievements
Rank 2
answered on 20 Aug 2013, 12:32 AM
Okaay.. i just commented out caching, and still facing same problem: when i'm visiting page first time, everything is ok, but when i'm visiting the page for the second time, VirtualDataCollectionOnItemsLoading() calls 2 times, and 2 server requests are sent.

EDIT: I assume, something is wrong with async call. I'm using just a common Bcl library.. hm, maybe i should check for updates.

EDIT2: well, i used outdated Bcl indeed. However, problem is still there: updating didnt help.

EDIT3: digging deeper shows, that something is wrong with threading here. Admin, can you, please call here a guy, who was working on this stuff? I guess, my approach is incompatible with DataBoundListBox design.

I'm getting ReadFromCacheAsync() calls from different threads, but they are doing same stuff simultaneously.

EDIT4: Okay, last observation for this evening for me. I removed QueueUserWorkItem() and asyncs - now VirtualDataCollectionOnItemsLoading() is calling only once. 
0
Vitalii
Top achievements
Rank 2
answered on 20 Aug 2013, 08:21 AM
Well.. i have an idea to workaround this, to try to use BackgroundWorker. But afaik, async is more suitable for waiting tasks, and BackgroundWorker is more suitable for Cpu-intencive tasks. 

EDIT: okay, i tried this one
private Task<ProductSubSubCategoriesAnswer> Process(int a, int b)
        {
            return TaskEx.Run(() =>
                {
                    var res = _dataService.RequestServerAsync(SelectedIndex, a, b);
                    return res;
                });
        }
 
        private async void VirtualDataCollectionOnItemsLoading(object sender, VirtualizingDataCollectionItemsLoadingEventArgs e)
        {
            //BusyLevelInc();
            if (String.IsNullOrEmpty(SelectedIndex)) return;
 
            var an = await Process(e.StartIndex, e.Count);
 
            if (an.Status == AnswerDataServiceStatus.Ok) // && answer.Collection.SequenceEqual(VirtualDataCollection.))
            {
                    lock (locker)
                    {
                        VirtualDataCollection.ItemsLoading -= VirtualDataCollectionOnItemsLoading;
                        VirtualDataCollection.Count = an.TotalItems;
                        VirtualDataCollection.LoadItems(e.StartIndex, an.Collection);
                        VirtualDataCollection.ItemsLoading += VirtualDataCollectionOnItemsLoading;
 
                        IsBusy = false;
                        Status = String.Empty;
                    }
                 
            }
}

But still having same issue: when i'm visiting page for a second time, _dataService.RequestServerAsync(SelectedIndex, a, b); is calling twice. :(
0
Vitalii
Top achievements
Rank 2
answered on 20 Aug 2013, 09:30 AM
Tried BackgroundWorker - still same crap: while visiting page for a second time, it sends 2 server requests.

var bw = new BackgroundWorker();
 
            bw.DoWork += async (o, args) =>
                {
                    var res = await _dataService.RequestServerAsync(SelectedIndex, e.StartIndex, e.Count);
 
                    if (res.Status == AnswerDataServiceStatus.Ok) // && answer.Collection.SequenceEqual(VirtualDataCollection.))
                    {
                        DispatcherHelper.CheckBeginInvokeOnUI(() =>
                            {
                                lock (locker)
                                {
                                    VirtualDataCollection.ItemsLoading -= VirtualDataCollectionOnItemsLoading;
                                    VirtualDataCollection.Count = res.TotalItems;
                                    VirtualDataCollection.LoadItems(e.StartIndex, res.Collection);
                                    VirtualDataCollection.ItemsLoading += VirtualDataCollectionOnItemsLoading;
 
                                    IsBusy = false;
                                    Status = String.Empty;
                                }
                            });
                    }
                };
 
            bw.RunWorkerAsync();

EDIT: made basic test again: if to comment away all async stuff in VirtualDataCollectionOnItemsLoading(). everything works fine: it is called only once.
But i don't want to return to bloody callbacks because of this, there should be other workaround...

0
Vitalii
Top achievements
Rank 2
answered on 20 Aug 2013, 04:52 PM
Well... i ended up with moving cache reading to non-async.. page loads quite slow, about 0.5 sec, but that's much better than 2 seconds

But now i got another problem: paging is failed to work. VirtualDataCollectionOnItemsLoading() is not calling. 
Guys, can you, please, provide a sample of using DataBoundListBox with cache? I expected to spent at most an hour attaching cache, but now i had spent the whole day on it.

0
Vitalii
Top achievements
Rank 2
answered on 21 Aug 2013, 08:02 AM
Well.. now it works more or less, but caching (just reading file from isostorage and parsing it) freezes page for about 0.5-1 second. On the other pages, it work immediately.
Taking into account, that server request takes 1-1.5 seconds, it is easier not to use cache at all.

I hope, you're planning to do something with it in the nearest future :)
0
Deyan
Telerik team
answered on 21 Aug 2013, 02:23 PM
Hi Vitalii,

Thanks for writing.

Since the thread has become a bit longer, we would like to kindly ask you to summarize the difficulties you are facing so that we can review them and be able to assist you quickly.

Thanks for your understanding.

Regards,
Deyan
Telerik
TRY TELERIK'S NEWEST PRODUCT - EQATEC APPLICATION ANALYTICS for WINDOWS PHONE 7.
Learn what features your users use (or don't use) in your application. Know your audience. Target it better. Develop wisely.
Sign up for Free application insights >>
0
Vitalii
Top achievements
Rank 2
answered on 21 Aug 2013, 02:33 PM
Thanks for answer.
Can you, please, provide a sample of VirtualDataCollection (using auto mode) with caching, additionaly to loading.
Once page is loaded, results should be stored to file, and when user visit page for a second time,it should be recovered.

The problem is that i have no idea, where to read data exactly, to avoid page freezes
0
Deyan
Telerik team
answered on 21 Aug 2013, 02:40 PM
Hello Vitalii,

Page freezes are caused by long-lasting operations performed on the UI thread. This is something you will face no matter whether you are using the VirtualizingDataCollection or not.

When you fetch data either from the Internet or from the local storage, you should make sure it is fetched asynchronously and delivered to the UI thread via a Dispatcher as soon as it arrives. From that moment on you can load it into the VirtualizingDataCollection without experiencing any issues.

Regards,
Deyan
Telerik
TRY TELERIK'S NEWEST PRODUCT - EQATEC APPLICATION ANALYTICS for WINDOWS PHONE 7.
Learn what features your users use (or don't use) in your application. Know your audience. Target it better. Develop wisely.
Sign up for Free application insights >>
0
Vitalii
Top achievements
Rank 2
answered on 21 Aug 2013, 02:46 PM
That's why im using threading.
Anyway, I'll just send you sample project, so you would be able to take a glance :)
0
Deyan
Telerik team
answered on 21 Aug 2013, 02:53 PM
Hello Vitalii,

Thanks for your understanding.

To be able to attach a project you will have to open a new support thread. Since you've already done that, you can send us your project there and we will close all other threads.

Thanks for your time.

Regards,
Deyan
Telerik
TRY TELERIK'S NEWEST PRODUCT - EQATEC APPLICATION ANALYTICS for WINDOWS PHONE 7.
Learn what features your users use (or don't use) in your application. Know your audience. Target it better. Develop wisely.
Sign up for Free application insights >>
Tags
DataBoundListBox
Asked by
Vitalii
Top achievements
Rank 2
Answers by
Vitalii
Top achievements
Rank 2
Deyan
Telerik team
Share this question
or