I have a form with two panels(top, bottom), each panel contains grids. Basically, it's a Master-Detail form where selecting a row from the top grid would show details in the bottom grid.
Binding the data to the detail grid is taking some time. Since binding is done on UI thread, it blocks the thread and therefore the user cannot select another row from the master grid until the binding is done.
Please note that by binding I don't mean getting data from data source. It's the actual binding that's taking longer as it does a lot of data massaging. How can I keep the UI thread free while the detail grid is doing it's binding?
Thanks a million.
You can't. The update of the UI has to be performed on the UI thread.
You may be able to speed up the binding by using things such as BeginUpdate/EndUpdate which is available on some controls but as you don't specify what you are using I can't say if that's available.
You can use a background thread to perform your data retrieval, then use the UI thread to display it.
If I were you, it sounds like you are dealing with a LOT of data, and I would separate all the "massaging" you can into a separate thread process.
So maybe for example when a master record is created, you "manually" spin off the detail data in a background thread to another dataset and do the massaging, then just bind the resulting dataset to the grid. That way the only thing taking place on the UI thread is just the UI binding.
Ultimately if it's taking that long, you may be approaching a critical point in your application where you need to manually do what you need to do in code rather than using the out of the box data binding features in .NET.
Finally I found the solution. The solution doesn't include multithreading to start with. As I said that the delay was in binding the grid meaning the main thread was held, we couldn't do much. So the solution is to bring delays. When user selects the master row, a timer ticks off for a certain time. If another request is made before the time is expired, timer gets restarted. This is we ignore all calls that are made because user was clicking or selecting rows too fast. Once timer is expired, I take the selected row and display data. Simple and elegant solution.
Related
i have a stored procedure which is taking 10 seconds to pull 30 records from a table after long processing.Each datalist item has many controls within which are to be data bound while binding those 30 records to the datalist, which is also taking a bit long.
I want to know if we can assign this job to a thread??
Please help,thanks in advance!!
Each datalist item has many controls within which are to be data bound
while binding those 30 records to the datalist, which is also taking a
bit long.
Binding a UI control, shall always be on the UI thread
I want to know if we can assign this job to a thread?
Simple answer is no for a UI control
Option for you would be an in memory data collection can be updated on a thread, but you need to make it thread safe either using a thread safe collection or a using a construct like lock
Final Data binding will always be on UI thread, else it will lead to exception
I have a list of Customers and I update my DataGrid's ItemsSource to contain the customers list.
The problem is that after changing the ItemsSource, the thread update all binding targets to the values in each customer object, and this action freezes the UI for more than 30 seconds.
To solve this I tried to change the ItemsSource property in another Thread but the new thread can not access the datagrid control which owned by the UI thread.
If I put the ItemsSource changing code in Invoke methode the UI will freeze again.
//The following code is handled in another thread
// Geting a list of Customers
List<Customer> customers = manager.AllCustomers.SearchCustomers(fName, lName, address, city, tz, phone);
//Changing the DataGrid ItemsSource
Dispatcher.Invoke(() => customersSearchResultsDG.ItemsSource = customers);
//UI Thread is freezing until ItemsSource Changing complete
p.s
The amount of time it thinks not really bother me because I created a loading animation control.. but the freezing makes the animation stuck and that is what i'm trying to fix.
When the UI thread in a WPF Application is busy, the UI will appear to freeze. There is nothing that can be done about that, but to avoid this situation, we typically do as much long running work as possible in background threads. However, as you have discovered, you cannot manipulate UI elements from a background thread, so there is only so much that we can do.
Other things that we can do to minimise the amount of time that the UI thread is busy is to use Virtualization, container recycling, freezing resources and/or optimise used Templates. You can find out more about this from the Optimizing Performance: Controls page on MSDN.
However, with the small number of items in your collection, it would seem to me that either you are loading and/or preparing your data extremely inefficiently, or you have incredibly large and complex DataTemplates to define your items. The links provided above should help you if your problem is the latter.
I'm making a media stats application and it has a TreeView control with all media files as items. It takes several seconds to populate it and I'm thinking there has to be another way to show items at any scrollbar position without taking that much time.
Accessing controls from threads other than those they were created on (UI thread) is prohibited, so it's either the usual approach with a noticeable freeze, or some other way I can't come up with.
How do I populate a TreeView control with many items without stalling the UI thread for a long time?
Don't load all of the items at once. Load only what they need to see at any given point in time (so at first, only the top level), and then when any given item is expanded (there is a relevant event for you to add a handler for), dynamically populate the next level. When an item on that next level is expanded, expand one level down, etc.
Use your UI thread's Dispatcher from another thread with a lower priority.
Or you could implement it differently. Show VMs linked to the Items, which are still loading in the background, and update the VM when the item is finished loading.
Or only load X amount at a time, pages of items.
I want to be able to add items to a Data grid at a fast rate without causing UI delay.
Here is what I am doing now:
I am using an ObservableCollection that is bound to the data grid.
I use a background thread that loops and calls Invoke on the current dispatcher only when inserting/removing from the observable collection. Calling BeginInvoke instead has undesirable results.
I know that invoking that much on the dispatcher is causing the delay but I don't know what else to do. I have used background workers before but I don't think that applies to my scenario.
What can I do to keep the UI responsive?
Batch the updates -- the background thread could add items to a queue and you can periodically refresh your bound observable collection by invocation. Take a look at the System.Collections.Concurrent namespace if you need to handle multi-threaded producers
A major weakness in your design is that by binding to an ObservableCollection, you are causing the UI to render every item that get's added to the list (possibly thousands) - even if at the end of processing there are only 10 items which need to be rendered.
I saw huge improvements by changing the ObservableCollection to a List, and refreshing the DataGrid manually at the end of processing - this way the UI only ever needs to process 10 items. I found that this change caused a 50% performance gain, as well as allowing the UI to be 100% responsive while the List is being processed.
If you are processing the list for a long time, and need to show live changes, you could refresh the DataGrid every 100 items. This would show results with about 0.5 second accuracy which should be close enough.
I'm using the DevExpress Xtra TreeList control to display a hierarchical set of questions and responses - think of a complex survey form, containing sections, subsections and a variety of questions.
The form is working in unbound mode, with no dataset nor any databinding.
As a part of the information displayed for each question, some background is obtained by calling a webservice on a background thread; results from these webservice calls are then used to populate the TreeList via calls to TreeListNode.SetValue().
Presently, these calls to SetValue() are causing any active editors to close, discarding the user's current input - a very user unfriendly experience.
How can I ensure the user's editing process is unaffected by these background updates?
The only similar questions I've found have been on the DevExpress forums, where the suggestion is a forced commit of the user's entries, which avoids loss of data but otherwise does nothing to fix a poor user experience. Since these all dated from 2007, I'm hoping the situation has now changed. Is it possible to update nodes without altering the state of the users own activity?
Background: A typical screen would have 500+ rows, with the webservice call for for each row taking around 0.6s to return. Forcibly committing or cancelling the user's actions every 0.6s is simply not acceptable, and forcing users to wait for processing to complete (>5minutes) before they can make any changes is equally poor.
Short answer: You can't
Changing a value in the TreeList will result in any current user editing being cancelled, reguardless of the use of Binding or not.
Official response from DevExpress:
Unfortunately, there is no way to prevent an active editor from being closed when the data source values are changed. It is impossible to achieve because the TreeList should be always synchronized with the underlying data. This functionality is implemented via the IBindingList interface in a usual manner. In response to the "change" notification the treeList must refresh itself and, as a result, reload data. This causes the active editing state to be reset.
However, there are several different ways to introduce required functionality. For example, you can create a separate form that will contain a set of editors that will provide the ability to edit a specific object directly. Another possible way to achieve this goal is to create some intermediate storage that will cache all changes. The synchronization with the TreeList's data source should be performed by user request.
Well one way i achieved to do it is by ShowEditor() after a small time delay after an event which does an update (say 100 miliseconds). I would get a problem because of an notifypropertychanged update and i would hook on FocusedNodeChanged. For instance:
FocusedNodeChanged += OnNodeChanged;
private void OnNodeChanged(object s, FocusedNodeChangedEventArgs e)
{
_delayer.Start();
}
private void _delayer_Tick(object sender, EventArgs e)
{
ShowEditor();
_delayer.Stop();
}
_delayer is a Timer class with tick event. A bit crude but it does the trick.