This is my requirement:
On a button click I need to get the data from database and populate in a datagridview, for which I'm using a function. As the retrieval may take a long time and I want to use the UI meanwhile, I want this function to run in a separate thread.
For this, I'm using async callback. But between the begininvoke() and endinvoke() function. I'm not writing any code (I don't know what to write to make the UI respond).
The datagridview is getting populated correctly but the UI is blocked when I'm trying to access it when the function is retrieving the data.
I'd recommend not to start the long running operation from the UI thread. Start another thread first, and then do the long running operation in that separate thread. When it is done, post the results back to the UI using the Form.Invoke() method. This way, the UI thread is not affected directly.
Instead of creating another thread by hand, you can also use a construct like BackgroundWorker.
If you do start the long running operation from the UI thread, you'd need to call Application.DoEvents() periodically (e.g. inside a loop). However, if the long running operation is an IO intensive -- meaning you are waiting for an IO operation most of the time -- then you won't get to call Application.DoEvents() as often as you'd like. This will make the UI seem less responsive or jerky. The seperate thread, as I mentioned above, is a better way in this regard.
If you are using a loop to Populate your DataGridView, You can use the Method Application.DoEvents() inside your loop to make your UI remain Responsive during the population of the DataGridView.
Update
As you stated the problem is not the loop, I think the best approach will be using the BackgroundWorker class.
Where you can populate the DataGridView in the DoWork() event of the BackgroundWorker
And you can start the BackgroundWorker.DoWork() event during the button_click event of your Code!
First of all, i should create asynccallback function in the UI form itself, not in middle level which is, in my case , DataMgr.
Also, i should add the last two parameters for begininvoke function with appropriate values where i have passed null values.
It should be
MethodDelegate dlgt = new MethodDelegate(DataMgr.countIssuingEntities);
TempValueHolder tmp = new TempValueHolder();
AsyncCallback cb = new AsyncCallback(MyAsyncCallBack);
IAsyncResult ar = dlgt.BeginInvoke(issueGroupId, element.ControlType, (EvaluatingEntityCombo.SelectedItem as CIQHydCore.RefData.RefDataInfo).Id, (IssuingEntityCombo.SelectedItem as CIQHydCore.RefData.RefDataInfo).Id, str1, str2,**cb,dlgt**);
and in MyAsyncCallBack function we need to populate the datgridview with the retrieved values from the end
Related
I have a piece of code testing the GUI and threading behavior. I want to keep ProgressBar animation running (with IsIndeterminate="True") as I query the database and add a large number of rows (10K+) into the DataGrid. Even if I wrap the database and GUI code in Dispatcher.BeginInvoke, the ProgressBar animation would jerk as the DataGrid is being filled.
I would expect the ProgressBar animation would either freeze (if on GUI thread) or run smoothly (if on a separately thread), but I cannot understand why the animation is running jerkingly.
Please do not suggest BackgroundWorker, as I want to understand the problem in this question, and why BeginInvoke is not separating the threads. I simply loop through SqlDataReader and add to DataGrid as Item one by one instead of databinding to a source or a datatable.
// XAML
<Button Click="Button_Click"></Button>
<ProgressBar IsIndeterminate="True"></ProgressBar>
<DataGrid ... ></DataGrid>
// C#
private void Button_Click(object sendoer, RoutedEventArgs e)
{
this.Dispatcher.BeginInvoke(DispatcherPriority.Normal,(ThreadStart)delegate()
{
// Query database and update GUI (e.g. DataGrid)
});
}
The Dispatcher always executes code on the thread it is associated with (the UI thread in your case), regardless of whether you use Invoke or InvokeAsync (which is a convenient shorthand for BeginInvoke). So all the work regarding loading data from database and updating the DataGrid is done on UI thread, hence the animation is not smooth.
The difference between Invoke and InvokeAsync is that the former is executed synchronously, and the latter is executed asynchronously. What it means is that in the first case the calling thread will be suspended until the delegate has finished executing (i.e. it will be synchronized), whereas in the second case the thread will continue its execution without waiting for the delegate to finish. Let me try to point out this difference using examples.
Example I. The methods are called from the UI thread (as in your case)
Let's assume we only have one thread (the UI thread). Calling Invoke will not have any noticeable effect, since the delegate will be executed immediately and only then the execution will continue. So this:
Dispatcher.Invoke(() => DoSomeStuff());
DoSomeOtherStuff();
will have the same effect as this:
DoSomeStuff();
DoSomeOtherStuff();
Calling BeginInvoke however will have an effect such that the delegate will be scheduled to execute only after all scheduled tasks with higher priority (or already scheduled with the same priority) are executed. So in this case:
Dispatcher.InvokeAsync(() => DoSomeStuff());
DoSomeOtherStuff();
DoSomeOtherStuff() will be executed first, and DoSomeStuff() second. This is often used for example in event handlers where you need some code to be executed only after the event is completely handled (e.g. see this question).
Example II. The methods are called from a different thread
Let's assume we have two threads - the UI thread, and a worker thread. If we call Invoke from the worker thread:
Dispatcher.Invoke(() => DoSomeStuff());
DoSomeOtherStuff();
first DoSomeStuff() will be executed on UI thread, and then DoSomeOtherStuff() will be executed on worker thread. In case of InvokeAsync:
Dispatcher.InvokeAsync(() => DoSomeStuff());
DoSomeOtherStuff();
we only know that DoSomeStuff() will be executed on UI thread and DoSomeOtherStuff() will be executed on worker thread, but the order in which they will be executed is indeterminate*.
Usually Invoke is used when your delegate yields some result and you need it to continue execution on the worker thread (for example when you need to obtain a dependency property value). InvokeAsync on the other hand is usually used when the delegate does not yield any result (or the result is ignored), such as in your case - updating DataGrid does not yield any result worth waiting for so you can immediately continue to load the next batch of data.
I hope that sheds some light on the issue for you and you can see why the solution to "jerky UI" is to delegate heavy work to another thread and only use dispatcher to interact with UI. That's were suggestions to use BackgroundWorker or Task come from.
*Actually they probably will be executed simultaneously. What I meant was if for example both methods only print some text to console, the order of messages in the console is indeterminate.
Recently decided to write a "quick" windows form app to tag my MP3 files. Not done anything with parallelism since .Net 3.0, so I'm looking at the Parallel.ForEach method to deal with the UI locking I get when I'm using a standard foreach statement. Here's an excerpt:
var i = 1;
var files = new List<string>(); // File list is populated using recursive method.
foreach(var f in files) {
// Add a row
var row = dgvList.Rows[dgvList.Rows.Add()];
// Update label
lblSummary.Text = string.Concat("Processing... ", i);
// Do things with row
// Increment progress bar
progressBar.PerformStep();
i++;
}
I've figured out the simple usage of Parallel.ForEach(), but I'm not sure I should be using that particular method to update the UI? Any suggestions?
You shouldn't use Parallel Libraries from your UI thread. The parallel library runs a group of tasks on multiple threads so you shouldn't write any UI related code inside it.
What you should do is move your business logic to background tasks and update the UI using dispatcher that will execute it on UI thread
as MSDN says
It is important to keep your application's user interface (UI) responsive. If an
operation contains enough work to warrant parallelization, then it likely should not
be run that operation on the UI thread. Instead, it should offload that operation to
be run on a background thread. For example, if you want to use a parallel loop to
compute some data that should then be rendered into a UI control, you should consider
executing the loop within a task instance rather than directly in a UI event handler.
Only when the core computation has completed should you then marshal the UI update back
to the UI thread.
and most importantly if you try to update UI thread from Paralle.Foreach
If you do run parallel loops on the UI thread, be careful to avoid updating UI
controls from within the loop. Attempting to update UI controls from within a parallel
loop that is executing on the UI thread can lead to state corruption, exceptions,
delayed updates, and even deadlocks, depending on how the UI update is invoked
You should be very careful with thread-safety.
You should be make sure to lock any object you are using, and unlock it appropriately.
Otherwise, there should be no problem I know of using Parallel.ForEach for UI.
EDIT: you can set Form.CheckForIllegalCrossThreadCalls=false to disable check for thread-safety.
Here's some documentation: http://msdn.microsoft.com/en-us/library/system.windows.forms.control.checkforillegalcrossthreadcalls.aspx
This will work, but it is dangerous, because then you need to care about your thread-safety by yourself.
A better way to deal with this is to use the invoke-pattern for the UI-logic, but then parallelism will suffer, as the UI operation itself will be called on the UI thread.
It is, however, the safe way to do things.
Documentation: http://msdn.microsoft.com/en-us/library/ms171728.aspx
OK, I found the best way to achieve this is by running something like this:
// Kick off thread
Task.Factory.StartNew(delegate{
foreach(var x in files) {
// Do stuff
// Update calling thread's UI
Invoke((Action)(() => {
progressBar.PerformStep();
}));
}
}
I actually updated my code to populate a List within the foreach loop, then assign that to the daragrid via .DataSource, instead of working with the .Rows collection directly. Should have done that from the start really :)
I have a lot of long-running activities and think that spawning this activity off to another thread will be a good way to have my U.I be able to update to show its current status.
However, when I use the following:
Thread t = new Thread(() =>
{
/* do magic here */
});
Nothing inside the foreach loop that's inside the thread gets done. But, when I don't use a thread, the work does get done, so I know it's not a problem with the loop.
Any suggestions?
You may also want to take a look at BackgroundWorker as it nicely encapsulates everything.
Are you even starting the thread?
newThread.Start();
In the sample you provide you merely declare it.
Also bear in mind that if you're using WinForms, you won't be able to update the UI directly from any thread other than the one that created it; for example, modifying a progress bar or label control from within your foreach loop.
You need to start the tread, t.Start();
Creating the instance just creates an managed wrapper for a thread. Calling Start will set things in motion and eventually make your code run on a separate thread.
Probably you haven't started the thread, so its not running yet.
However, in your case its usually better to use BackgroundWorker class, this will create the thread for you and provide thread-safe way to update the UI with the progress of the threads work.
I have a WinForm drawing a chart from available data.
I programmed it so that every 1 secong the Winform.Timer.Tick event calls a function that:
will dequeue all data available
will add new points on the chart
Right now data to be plotted is really huge and it takes a lot of time to be executed so to update my form. Also Winform.Timer.Tick relies on WM_TIMER , so it executes in the same thread of the Form.
Theses 2 things are making my form very UNresponsive.
What can I do to solve this issue?
I thought the following:
moving away from usage of Winform.Timer and start using a System.Threading.Timer
use the IsInvokeRequired pattern so I will rely on the .NET ThreadPool.
Since I have lots of data, is this a good idea?
I have fear that at some point also the ThreadPool will be too long or too big.
Can you give me your suggestion about my issue?
Thank you very much!
AFG
It is a good idea to move the fetching of the data to a Thread. You can use a BackgroundWorker that gets the data in an endless loop and
use the UpdateProgress event to update the chart. This takes care of the InvokeRequired business
Use a Sleep(remainingTime) inside the loop to get a desired frequency.
It is quite unlikely you'll be ahead by using a background timer. Your chart control almost certainly requires it to be updated from the same thread is was created on. Any kind of control that has a visible appearance does. Which requires you to use Control.BeginInvoke in the Elapsed event handler so that the update code runs on the UI thread. Dequeueing data isn't likely to be expensive, you will have actually have made it slower by invoking. And still not have taken the pressure off the UI thread.
You'll also have a potentially serious throttling problem, the timer will keep on ticking and pump data, even if the UI thread can't keep up. That will eventually crash your program with OOM.
Consider instead to make the code that updates the chart smarter. A chart can only display details of the data if such details are at least a pixel wide. Realistically, it can only display 2000 pixels with useful information. That's not much, updating 2000 data points shouldn't cause any trouble.
I would go with a System.Timers.Timer over a BackgroudWorker in an endless loop.
The BackgroundWorker is executed from a ThreadPool and is not meant to run for the lifetime of your application.
Motivation for System.Timers.Timer:
Each elapsed event is executed from a ThreadPool, won't hang your UI thread.
Using a combination of locks and enabling/disabling the timer we can get the same frequency as if we did a Thread.Sleep(xxx) in an endless loop.
Cleaner and more obvious as to what you are trying to achieve
Here's my suggestion:
Disabling the timer at the beginning of the method, then re-enabling it again at the end, will cater for the case where the amount of work done in the elapsed event takes longer than the timer interval. This also ensures the timer between updates is consistent. I've added a lock for extra precaution.
I used an anonymous method to update the UI thread, but you can abviously do that however you want, as long as you remember to Invoke, it's also a good idea to check the InvokeRequired property
private readonly object chartUpdatingLock = new object();
private void UpdateChartTimerElapsed(object sender, ElapsedEventArgs e)
{
// Try and get a lock, this will cater for the case where two or more events fire
// in quick succession.
if (Monitor.TryEnter(chartUpdatingLock)
{
this.updateChartTimer.Enabled = false;
try
{
// Dequeuing and whatever other work here..
// Invoke the UI thread to update the control
this.myChartControl.Invoke(new MethodInvoker(delegate
{
// Do you UI work here
}));
}
finally
{
this.updateChartTimer.Enabled = true;
Monitor.Exit(chartUpdatingLock);
}
}
}
i've made a C# winforms application. Now i have a form which has lots of buttons, which call huge number crunching functions whose output i update in a textbox. I call the textbox.begininvoke() method to which i pass a delegate to the function which updates the text in the textbox, however when the text is huge, the form is non responsive as i can't click on the cancel button. Isn't there any way so that the whole form remains responsive and as well the update too keeps happening. I have to show the data to the user as it is coming, i can't buffer the whole thing and show in the end. I also tried to implement my own buffer and show data at particular intervals which works great for small amount of text, but in huge amount the UI just doesn't respond.
any help?
Thanks
updating question as some confusions are arising
i've called the number crunching function on a separate thread.
that number crunching function calls the control.begininvoke function whenever data arrives to update the textbox
MY UI gets to be displayed and i see the output coming, but when the data is huge, i can't do any other activity though i can still see the UI
Calling BeginInvoke (or Invoke) will not buy you anything unless the number crunching function is running on another thread than the UI thread.
Consider the following code:
private void HardWork(object state)
{
for (int i = 0; i < 10; i++)
{
Thread.Sleep(500);
SetText(i.ToString());
}
}
private void SetText(string text)
{
if (this.InvokeRequired)
{
this.Invoke(new Action<string>(SetText), text);
}
else
{
textBox1.Text = text;
}
}
private void Button_Click(object sender, EventArgs e)
{
ThreadPool.QueueUserWorkItem(HardWork);
}
The Button_Click method will start executing the method HardWork on a separate thread. HardWork will do some processing (simulated by the Thread.Sleep call) and then call a method to display some progress. Inside this method, we need to check whether we are on the UI thread or not. If we are not, we invoke the same method using Invoke (or BeginInvoke) in order to force it to execute on the UI thread.
Update: if the amount of data emitted from the number crunching method is very large, this might of course have a negative impact on the UI responsiveness. If you for instance accumulate a large amount of text in your threaded method and emit that text on every update, that will be slower than just emitting what has changed since the last update. The same goes for the text box; calling TextBox.AppendText with just the new text will be faster than repedetly assigning the TextBox.Text property.
It's hard to give more detailed ideas on how to solve your particular problem since we have not see what your code actually does.
You got it backwards.
BeginInvoke is what you should use to update the UI. It does not spawn a new thread, as you seem to believe.
BeginInvoke is simply "Execute the following within the thread that the control was originally created in", which is your UI thread.
BeginInvoke is therefore what you should use in your number crunching thread to post back updates into the UI.
Hope this helps
Have the function that updates the text box do it piece by piece and call DoEvents between each update. That is, break up the string and ...
update piece 1
DoEvents
update piece 2
DoEvents
...
update piece n