I've got an SQL query that returns hundreds of rows, and I need to add them to a WinForms DataGrid in a way that will still allow the user to view/scroll the DataGrid as the rows are added.
Currently I'm using a BackgroundWorker thread to execute the SQL statement and loop through the rows in a DataReader, before using Control.BeginInvoke to pass each new row back to the UI thread where it is added to the DataTable that's bound to the DataGrid. This isn't really having the desired effect (it takes a little while to update the DataGrid, and then after it does one update the UI becomes unresponsive).
Is there a way to do what I want, and if so how?
Edit: I've added a thread.sleep to the worker thread as it loops through the datareader, which stops the UI from becomming unresponsive after the first update, but it's still not as responsive as I would like it to be (scrolling is a bit jumpy as adding a row in the ui thread seems to steal focus).
Have you looked at virtual mode for DataGridView controls? It can offer some way of iterating only the rows you need to view (i.e. only get data when the user scrolls).
See: http://msdn.microsoft.com/en-us/library/ms171622.aspx
PS: DataGrid is old, try DataGridView :)
Currently I'm using a BackgroundWorker thread to execute the SQL
statement and loop through the rows in a DataReader, before using
Control.BeginInvoke to pass each new row back to the UI thread where
it is added to the DataTable that's bound to the DataGrid.
It seems that you are using Dispatcher to update the UI. That's not a good idea. Using datagrid in multithreaded environment is tricky. I have published a template here. It covers a possible approach on using datagrid in multithreaded setup.
http://www.codeproject.com/Articles/1086714/A-Template-For-Using-Datagrid-in-Monitoring-UI
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 am working on a application which downloads using
1) Parallel.ForEach(linklist, x => DownloadAsync(x));
2) webClient.DownloadStringAsync(new Uri(link.Url));
class Link
{
string url;
string result;
int progress;
}
and updates the datagridview using INotifyPropertyChanged.
The problem is that the download is real fast, the datagridview updates first row, then the UI does not update, but then on moving the mouse cursor on datagridview rows one by one each row updates values.
I don't understand where I am missing anything.
please any suggestings, thank you in advance.
EDIT: Async does not block the GUI, so i am not using background thread.
Although you don't show your code, I assume you are updating UI elements from backgroud thread, which is something you should never do. If you are targeting WinForms you need to use BackgroundWorker or Control.Invoke.
BackgroundWorker Component Overview
How to: Implement a Form That Uses a Background Operation
How can I update my user interface from a thread that did not create it?
Your objects, being bound, need to implement INotifyPropertyChanged.
I have a WinForms application that contains a Dataset ds and a DataGridView dgv. dgv is bound to ds.
ds is updated via a Task() that periodically queries a database using the TableAdapter.Fill() method. There are two issues that I am experiencing here.
When ds is updated, dgv is not refreshed unless a the window is resized or some other event causes a redraw of the form.
When a user begins to edit a cell in dgv, ds is updated and causes a UI crash due to multiple threads accessing the same GUI control. I have attempted using a flag, EditModeOn, which is set by certain events from DataGridView dgv, though this has not helped in preventing the thread errors.
What is the best way to have a DataGridView that can be edited by a user and is updated via changes to the bound dataset (which is updated in another thread)?
For your point #2, you can use the function Invoke from the Control class. This function will execute the function in the UI Thread.
http://msdn.microsoft.com/en-us/library/zyzhdc6b.aspx
Ex. :
// Invoke an anonymous method on the thread of the form.
this.Invoke((MethodInvoker) delegate
{
//Call your function to update your datagridview with the dataset in parameters
...
});
On point #1, you can fix this pretty simply by calling Form.Invalidate(). This will cause your form to repaint itself; that's a bit dirty but it should do the trick.
On point #2, if you have a Task that is updating the contents of the control from another thread, then you should always get an exception since it is illegal to access a control from any thread other than the UI thread (the thread he UI is created on). So I'm not quite clear how you're doing this.
But, what I would do is use the thread to retrieve the results and then store those results in a member variable (field). Then periodically check that field to see if the data needs to be refreshed, and if take the data from the field and put it into your grid, and then null out the field. You can use the Tick event of a System.Windows.Forms.Timer class to implement this periodic check.
In your update routine, you can check your flag to see if the grid is being edited, and ignore the updates until later.
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.