Silverlight UI Thread Freezing - wpf

I have a grid control that is trying to display large amounts of data and so it takes a long time to render on the UI thread.
I have added a loading bar that animates and displays depending on if the screen is busy or not (is rendering).
However the loading bar is just freezing when the grid is trying to render. I am assuming this is because there is only one UI thread and that thread it busy.
Does anyone know a way in which I can keep the loading bar animated?
Many thanks,
Matt

You need to process the enumeration or data fetching from UI rendering, do the processing part for get the data ready for UI rendering on separate thread.
http://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx

If you insist on the grid rendering all the data at once, it all depends on whether the grid's rendering code can "yield" or not, kind of like the old Windows Forms "DoEvents()" method. It sounds like it's implemented in such a way that it doesn't, in fact, yield processing back to the UI thread during its rendering, and hence your progress bar never gets updated.
Does the grid ever call into your own code while it's rendering its content? If so, you could use those instances to update the state of the progress bar.
Have you looked into virtualizing the contents of the grid? You can get UI virtualization basically for free if you wrap the FrameworkElements that you need rendered in a VirtualizingStackPanel. If you want somewhat more complexity, you can also get data virtualization by wrapping your dataset with a PagedCollectionView class, and then writing . See here for more details. See also here for another (simpler?) way of implementing the same sort of virtualization.

Related

Suspend painting of underlying grid control

We are facing an issue, wherein we need to suspend grid painting for some time. We are using devexpress DXGrid bound to XPInstantFeedbacksource. We have a requirement of refreshing source every 2-3 seconds to get the updated realtime data which is huge (around 40 -50 thousand records in a day).
However the refresh method of the above mentioned source binds the grid asynchronously and when it does so, it causes some kind of flickering onto grid. Internally it captures layout of grid before refresh and renders it back in postrefresh phase.
I have tried many things like wrapping the refresh call in bigindataupdate and enddataupdate, but it doesn't seem to work.
However, one thing which looks interesting to me is using Win32 api to suspend layout painting for some moments and resuming it.
I found something at
How do I suspend painting for a control and its children?
which works well for Winforms, but in WPF as far as I know, individual controls share window handle. And method call
SendMessage(parent.Handle, WM_SETREDRAW, false, 0);
uses control handle to interact with WIN32. Also, I observed that if I suspend layout for window underlying grid still gets painted which is strange to me.
I just want to know , if I am going in right direction by suspending grid layout to avoid flickering and if yes please suggest some way to achieve this.
Thanks,
Gurpreet

Progress bar during load of virtualised wpf datagrid

I am using the normal WPF DataGrid to display some data from a REST feed. The REST feed is paged with a next link that contains the URL for the next set of items. The DataGrid is virtualised by having a custom object that implements the IList interface (not IList), and knows how to fetch missing data from the REST feed.
The issue is that if a user scrolls immediately to the bottom this component must do a bunch of REST requests for each "next" page, causing the GUI to freeze. Of course I could simply put up a "wait" screen, but I would actually be able to show an accurate progress bar.
So to accomplish this I have a progress bar on my application status bar that has visibility set to IsLoading on the data context, which in turn passes this down to the paging object. There is another property LoadedPercentage which shows how much of the required data has been loaded.
The issue is that when I scroll to the end of the screen, it still freezes and shows nothing. I set breakpoints in the code to see if my properties were being accessed and they were all hit at the correct times and showed the correct values. So I deduce from this that the DataGrid itself is somehow stopping the GUI thread from doing any drawing while it waits for the IList object to return the requested object.
So does anyone know of a solution for getting the status bar to show up? I would really rather have the status bar appear and track progress rather than some "loading please wait" screen. Can this be done at all with the built in objects or do we have to purchase some third party grid?
EDIT: It wasn't completely clear to some so I wanted to mention: I am doing virtualisation as described here among other places. It seems that when the DataGrid requests a specific entry it blocks the entire UI painting until it the request completes.
Well, UI is busy fetching data from the REST service. If you don't like the behaviour, you can implement data virtualization.
This post explains more: WPF Datagrid: Lazy Loading / Inifinite scroll
As far I know, there is no "ready" solution in WPF, and it will be little hassle, but it should work with some tweaking.
Implementing your custom IList doesn't sound like it would work, so I am not sure about how to "fix" your solution, and if it's even possible.

"Loading" animation priority

I am using an Infragistics XamDataGrid for my grid. It is bound to an ObservableCollection.
When a selection is made in a dropdown in the window, a request for data is made on a background thread and the loading animation is started. As the data is received, the necessary work is done, all on the background thread.
The issue I am facing is that once all of the data is ready, I need to update the collection that the grid is bound to. This needs to be done on the UI thread. So what happens is that while the XamDataGrid is doing its work on the UI thread to deal with the collection change, my animation stops animating.
As far as I can tell, there isn't much I can do since both the grid loading and animation need to occur on the same UI thread.
Is there anything I might have missed? Some way to keep the animation running while the grid is working to display the new rows?
The first thing I would do is figure out where the performance cost is. Simplify your UI and use WPFPerf to try and figure this out. You may find that you have a particularly expensive data template in your grid, for example.
If you still have performance problems, you can batch your updates into small groups, running each in their own dispatcher message. Pseudo-code:
// running on BG thread
var data = server.GetTheData();
// have the data, so marshal back to the UI thread in batches of 5
foreach (var batch in data.Batch(5))
{
dispatcher.Invoke(..., batch);
}

Adding Canvas children in a for loop don't get displayed till loop is done

What the tittle says, I have lengthy for loop in which based on some conditions I add objects to a Canvas. I want the objects to show as they are added but they show after the loop is done? Does anyone know why and how I can fix this?
Also: the textbox.text property doesn't get updated too.
The UI won't update while you are tying up the UI thread, you need to return control to allow it to render.
You should try to move long-running operations to a background thread if possible - say using a BackgroundWorker - and update the UI every so often. This should result in a much more responsive UI.
If you really need to do some lengthy work on the UI thread (eg you're adding a large number of controls that are slow to render) you'll have to break it up into manageable portions. You can wait for the CompositionTarget.Rendering event to know when the UI has rendered and you can continue. But it's much better to offload work to a background thread if you can.

Can I change the Thread Affinity (Dispatcher) of a Control in WPF?

I want to create a control which takes a while to create (Pivot) and then add it to the visual tree. To do this i would need to change the dispatcher of the control (and its heirachy) before adding it to the VisualTree.
Is this possible? Are there any implications of walking the controls trees and setting the _dispatcher field via reflection?
AFAIK this only works with Freezable derived classes. The best solution I see is to create the control on the UI Thread and show a progress bar during creation. To make this possible you will have to create the control in portions an let the progress bar update itself once in a while. This not only necessary for the progressbar but also will make sure that you application does not block.
Pseudocode (execure in extra thread):
this.Dispatcher.BeginInvoke(UpdateProgress(0));
this.Dispatcher.BeginInvoke(bigControlBuilder.Build(0,25));
this.Dispatcher.BeginInvoke(UpdateProgress(25));
this.Dispatcher.BeginInvoke(bigControlBuilder.Build(25,50));
this.Dispatcher.BeginInvoke(UpdateProgress(50));
this.Dispatcher.BeginInvoke(bigControlBuilder.Build(50,75));
this.Dispatcher.BeginInvoke(UpdateProgress(75));
this.Dispatcher.BeginInvoke(bigControlBuilder.Build(75,100));
this.Dispatcher.BeginInvoke(UpdateProgress(100));
this.Dispatcher.BeginInvoke(this.Children.Add(bigControlBuilder.GetControl()));
Update:
To make complex control more responsive you could also try UI-Virtualization/Data-Virtualisation:
Only load and show those visual items of the data items that are currently visible to ther user. Do not load and show visual items that are scrolled offscreen are to small to see or are in any other way invisible to the user. Upon userinteraction unload items that become invisble, load items that become visible.
To answer your question, I suppose it is possible to set _dispatcher using reflection but I would not recommend it at all. There is a deeply ingrained notion in WPF of thread affinity and STA so I wouldn't mess with that.
bitbonk's approach is a good one.
Another approach we have used in a project of ours was to create a second UI thread and have a progress indicator be rendered by the second UI thread while the first UI thread is building the UI. As long as the progress bar stays in the visual tree owned by the second UI thread, you should be good.

Resources