Winforms using BackgroundWorker to cycle through Datatable - winforms

Please could you give me your thoughts on the following (especially if its advisable or not to do so)...
Basically, I can successfully import CSV data into a datatable and then bind that datatable to a datagridview. What I would like to do now is run through some validation checks for each row in the grid. Each row will have its data validated thru a Stored Procedure that will do a bunch of checks and return one of two values. I would then like to display this value in the last column (originally empty) of the grid, and then move on to the next row and repeat this action until all rows have been validated.
I hope this paints a clear picture of my intentions. In order to update the UI I would have to use the BackgroundWorker component, but am just concerned that this may not be the right way to go about it, and especially how to go about it.
Please advise me. Thank u!

For a long operation, a background worker is the best way to perform a long task without making the GUI freeze.
You can use the worker's event ProgressChanged event to update the DataGrid. Note that you will have to update the DataGrid using the Invoke method, since GUI must be updated from the correct thread and Invoke transfers your action from the BG's thread to the GUI's thread.

Related

Update UI control frequently with multiple threads

I have a DevExpress GridControl oneway binding to a tableview in the viewmodel. There are about 20 background threads querying data from databases and update the tableview individually. The update to the table view is guardard with lock for async update. Dispatcher is used for refreshing the main UI thread. I also have another button to cancel the database and update functions via CancellationTokenSource.
However, when the applicatoin runs, I have to click the cancellation button many times in order to execute code in the cancel command. In another word, the UI Main thread is busy refreshing the GridControl and it blocks the Cancel Button.
Is there a way to achive this function?
Edit: Found this method helps a lot await Dispatcher.Yield(DispatcherPriority.ApplicationIdle);
It simply gives other UI controls a chance to be executed.
Creates an awaitable object that asynchronously yields control back to the current dispatcher and provides an opportunity for the dispatcher to process other events. (MSDN)
AFAIK, UI stands for User Interface, where main part is User! User is not robot, it is a person, which uses your application. You do not need to query data updates so often on UI thread. Why do you need 20 threads for database query operation? You have the single GridControl, which can show only several rows at time on the screen, 20, 50, 100 (no more). So, I suggest you to have only one thread for reading data from database, and do it once per 2-5 seconds, in order to provide User with some interactivity. For this purpose, TPL - is the good choice. Using it with CancellationToken - is good way to support cancellation with your scenario. Between database queries you can do the following:
while (true)
{
myToken.ThrowIfCancellationRequested();
// database query here
myToken.WaitHandle.WaitOne(2000)
}
Also, before updating source collection, you can use the following:
GridControl.BeginDataUpdate();
//Update your source collection
GridControl.EndDataUpdate();
This will prevent DevExpress control from listening CollectionChanged event, or any other, because on each Add/Remove action DevExpress call UpdateLayout() method, which is no so fast as we want to.
if layout is invalid in either respect, the UpdateLayout call will redo the entire layout. Therefore, you should avoid calling UpdateLayout after each incremental and minor change in the element tree.

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.

RowValidating doesn't prevent leaving an invalid row

I have bunch of textboxes bound to a datagridview. I want to prevent users from leaving a row if invalid input is entered.
I tried both the RowLeave and RowValidating events. They both give me the data row user is entering, not the old one. Therefore, in the RowValidating events, when I set the event.cancel=true, it does not revert back to the old row.
Basically I need a way to capture the row the user is trying to leave, and I am not able to do it with any of the those events.
Thanks!!
Edit : I guess a silly way to do it is via rowEnter event. I imagine I can accomplish what I want with that, but all the purpose of those fancy events are lost...
Update : I think the problem is with the data binding. I can see the underlying datarow is locked but that is not reflected in the textboxes. Yikes..
Try CellValidating, I know this used to work for me.

Separate UI thread for details view using WinForms

Our app's master/details view uses a datagridview as the master, and a custom control as the details view. The details view takes a long time to compute and render, making cursoring up/down the master view painfully slow.
Therefore, we'd like the details view to run asynchronously (in a separate UI thread) with change notifications from the master.
Creating a form in a separate thread is relatively straightforward, as Application.Run takes a form parameter.
Is there a way to run a winforms control on a separate thread? I'm aware that native windows in different threads can have a parent/child relationship, just not sure how to set that up using winforms.
TIA,
Updating the UI from a Secondary Thread
http://msdn.microsoft.com/en-us/magazine/cc188732.aspx
Intuitively, you also ought to be able to accomplish the same thing by using a BackgroundWorker. The BackgroundWorker is designed to update UI things like progress bars while executing stuff in the background, and it can be cancelled during its operation.
Is the slowdown caused by the loading of the data, or the population of the UI itself?
Most of the time it's the former, so if that's the case, then the logic that does the data loading should be abstracted into a different thread. The UI code can live in the main thread since updates are quick. You could use either a Thread or a BackgroundWorker in this situation. The key is to separate your data loading from your GUI population.
If you are firing off the update of the detail view in code, you can greatly improve the usability by sleeping 500ms between the time that the user selects the master record, and the time you update the detail view.
This gives the user 1/2 second to scroll to the next record without the details view updating at all.
If you're taking a speed hit during rendering, you should consider suspending layout until the form has completed updating, and then refresh the visible display once at the end.
this.SuspendLayout();
// Do control stuff here
this.ResumeLayout();
If that doesn't help, try this:
[DllImport("user32.dll")]
public static extern bool LockWindowUpdate(IntPtr hWndLock);
//
LockWindowUpdate(this.Handle);
// Do control stuff here
this.Refresh(); //Forces a synchronous redraw of all controls
LockWindowUpdate(IntPtr.Zero);
http://social.msdn.microsoft.com/Forums/en-US/winforms/thread/8a5e5188-2985-4baf-9a0e-b72064ce5aeb

how to get the wpf toolkit datagrid to show new rows when bound to dataset

Is there a way to get the wpf toolkit DataGrid to show new rows when its bound to a DataSet? In other words, I have a DataGrid, I've set its ItemsSource to a DataTable, and everything seems to work fine, except I can't get the grid to show rows that I add to the DataTable programatically.
You can set the datagrid.ItemsSource to an ObservableCollection<T>.
ObservableCollection<YourItem> items = new ObservableCollection<YourItem>();
yourDataGrid.ItemsSource = items;
Then you should be able to just add to the collection to get the new rows to appear:
Edit: Based on updated info.
if (Dispatcher.CheckAcces())
{
// already on thread UI control was created on
items.Add(<your item>);
}
else
{
// update on same thread UI control was created on
// BeginInvoke would invoke a delegate which would call items.Add(<your item>)
Dispatcher.BeginInvoke(...);
}
See Dispatcher. All System.Windows.UserControl objects have a Dispatcher property.
I'm not sure how anyone would have figured this out, especially since I didn't mention it, but the problem was that I was updating the dataset from a thread other than the form's main thread, i.e. the thread that the grid was created on. You can do updates from another thread, but you can't do inserts, although I don't know why. If someone could shed some light on that, I'd appreciate it. My guess would be that the grid checks to see if the insert is coming in on another thread, and if so, it ignores it because that would cause an exception.

Resources