How to update UI (text fields) during long running function? - c#

I know that the question may not make sense, and I'm having a tough time trying to think of a way to explain it, so I will show a snippet of code to help. I'm using Winforms on visual studio express 2010:
private void button1(object sender, EventArgs e)
{
txtOutput.Text += "Auto-collecting variables. This may take several minutes";
string v = foo();
txtOutput.Text += "\n" + v;
string b = bar();
txtOutput.Text += "\n" + b;
txtOutput.SelectionStart = txtOutput.Text.Length;
txtOutput.ScrollToCaret(); //scrolls to the bottom of textbox
}
So basically, when the user clicks button1, I want "Auto-collecting variables..." to be displayed in the textbox, and then have foo() execute, display that, and then have bar() execute, and then display that.
What is currently happening is that foo() and bar() execute, and then everything is displayed all at once after foo() and bar() have executed (functions that take several minutes). Is there anyway to fix this, or is there a work around?
Edit: Version of C# is 4.0. If I update to 4.5 or 5.0, will computers without .NET 4.5/5.0 be able to run the .exe?

C# 5.0 makes doing this trivial.
Execute the long running tasks in a background thread using Task.Run and use await to execute the rest of the method as a continuation in the UI thread without blocking the UI thread for the duration of the asynchronous task.
private async void button1(object sender, EventArgs e)
{
txtOutput.Text += "Auto-collecting variables. This may take several minutes";
string v = await Task.Run(() => foo());
txtOutput.Text += "\n" + v;
string b = await Task.Run(() => bar());
txtOutput.Text += "\n" + b;
txtOutput.SelectionStart = txtOutput.Text.Length;
txtOutput.ScrollToCaret(); //scrolls to the bottom of textbox
}
You can do the same in C# 4.0 like so: (The first solution will be transformed by the compiler into something similar.)
private void button1(object sender, EventArgs e)
{
txtOutput.Text += "Auto-collecting variables. This may take several minutes";
Task.Factory.StartNew(() => foo())
.ContinueWith(t => txtOutput.Text += "\n" + t.Result
, TaskScheduler.FromCurrentSynchronizationContext())
.ContinueWith(t => bar())
.ContinueWith(t =>
{
txtOutput.Text += "\n" + t.Result;
txtOutput.SelectionStart = txtOutput.Text.Length;
txtOutput.ScrollToCaret(); //scrolls to the bottom of textbox
}
, TaskScheduler.FromCurrentSynchronizationContext());
}

Use the BackgroundWorker class to do your processing without blocking UI updates. It has events that can be used to transfer progress information to the UI thread.

Depending on the version of .NET, you can use BackgroundWorker (Pre 4.0) or Tasks (Post 4.0 - 3.5 with an add-on)...to name a few.
Backgroundworker Pseudocode:
var backgroundWorker = new BackgroundWorker()
method
{
//Update UI
backgroundWorker.RunWorkAsync()
}
asyncworkmethod
{
//do main logic
}
asynccompletemethod
{
//Update UI to say done
}
Task Pseudocode:
method
{
//Update UI
TaskFactory.StartNew(()=>DoWork).ContinueWith((previousTask)=>UpdateUIToSayDone)
}
And, if you are using 4.5, then you can use the async/await keyword, however that is just syntactic sugar around tasks (mostly...). Servy already has a decent example of this, though if you go that approach

Using a background process (read the other answers) is the correct way to go but if you are looking at a very quick workaround you can call Application.DoEvents() after updating the TextBox. In most cases this call will result in your form updating to reflect the changes you made.

txtOutput.Update() should do what you want, but you should consider using background thread to complete long running task without blocking UI thread.

Related

C# - ' Dispatcher.BeginInvoke(new Action(() => ' doesn't work within Winforms. CS0120 [duplicate]

I am trying to understand better how can I update a windows forms progress bar from an async operation but I am getting some unexpected behavior from that.
Basically I am having a button which should after is being clicked to update a progress bar and then set it back to 0 once the progress bar gets 100% updated.
This is my code:
private async void button1_Click(object sender, EventArgs e)
{
await CallMethodAsync().ContinueWith((prevTask) =>
{
prevTask.Wait();
progressBar1.Invoke(new Action(() => { progressBar1.Value = 0; }));
});
}
private static async Task ExecuteMethodAsync(IProgress<double> progress = null)
{
double percentComplete = 0;
bool done = false;
while (!done)
{
if (progress != null)
{
progress.Report(percentComplete);
}
percentComplete += 10;
if(percentComplete == 100)
{
done = true;
}
}
}
private async Task CallMethodAsync()
{
var progress = new Progress<double>();
progress.ProgressChanged += (sender, args) => { progressBar1.Increment(10); };
await ExecuteMethodAsync(progress);
}
Having this implementation the progress bar is not being updated at all even if I call "Wait()" on the operation that should update the value of the progress bar.
If i remove this part of code:
progressBar1.Invoke(new Action(() => { progressBar1.Value = 0; }));
the progress bar gets updated but it remains all the time like that, and I want to set it back to 0 once it was entirely filled so that I can update it again when I click again the button.
Could someone please explain me what am I doing wrong ?
One of the reasons async-await syntax was invented because it was difficult to follow the sequence of instructions when tasks were concatenated using functions like ContinueWith.
If you use async-await it is seldom necessary to use statements like ContinueWith. After an await, the thread already continues with the statements after the await.
If the button is clicked, you want to call ExcecuteMethodAsync. This function takes an IProgress, because it wants to report progress regularly. You want to call this function asynchronously, so whenever the function has to wait for something, it doesn't really wait, but returns control to you so you could do other things instead of really waiting, until you encounter an await, in which case your caller continues processing until he encounters an await, etc.
The nice thing with async-await is that the thread that continues after your call to an async function has the same context as the calling thread. This means that you can regard it as your original thread. No InvokeRequired, no need to protect data with mutexes etc.
Your function could be simplified as follows:
async Task CallMethodAsync()
{
var progress = new Progress<double>();
progress.ProgressChanged += OnProgressReported;
await ExecuteMethodAsync(progress);
}
private void OnProgressReported(object sender, ...)
{
// because this thread has the context of the main thread no InvokeRequired!
this.progressBar1.Increment(...);
}
private async void button1_Click(object sender, EventArgs e)
{
await CallMethodAsync();
}
So when the button is clicked, CallMethodAsync is called. This function will create A Progress object and subscribes on its Report event. Note that this is still your UI-thread. Then it calls ExecuteMethodAsync, which will regularly raise event Report, which is handled by OnProgressReported.
Because ExecuteMethodAsync is async, you can be sure there is somewhere an await in it. This means that whenever it has to await, control returns to the caller, which is CallMethodAsync, until is encounters an await, which in this case is immediately.
Control goes up the call stack to the caller, which is button1_click, where it immediately encounters an await, so control goes up the call stack, etc.
All these controls have the same context: it is as if they are the same thread.
An article that helped me a lot to understand async-await is this interview with Eric Lippert. Search somewhere in the middle for async await
Another articel that helped me a lot to learn good practices were this article by the ever so helpful Stephen Cleary and Async/Await - Best Practices in Asynchronous Programming also by Stephen Cleary
Your issue is happening because ExecuteMethodAsync(...) is not actually asynchronous.
Add the following before the while loop to make it asynchronous
await Task.Delay(1);
or enclose some synchronous portion of code (e.g. the while loop) into a:
await Task.Run(() => { ... });
or (the best one), add the following at the beginning of the function:
await Task.Yield(); // Make us async right away

C# Asynchronous Task for a Stock Ticker

I've been trying to learn more about asynchronous tasks and threading but not making a ton of headway.
I'm trying to load an "Engine" type of thread that will run in the background upon launch and be able to access the UI Thread to update variables, without hanging the UI Thread.
In the below code, Engine is called, and a Ticker object is created which holds the current value of (Litecoin/USD) called Last, also holds several other values that would be useful. This code successfully assigns the current value to label1.text. I don't necessarily need code but what approach would I take to create a ticker object in the background every second and update the UI thread with each new Ticker objects values.
Is this a good case for a background worker?
private void Form1_Load(object sender, EventArgs e)
{
Engine();
}
private void Engine()
{
Ticker ltcusd = BtceApi.GetTicker(BtcePair.LtcUsd);
label1.Text = "LTC/USD:" + ltcusd.Last;
}
EDIT:
If I do the following, label1 throws an InvalidOperationException due to a Cross-thread operation attempt (label1 in the UI thread).
private void Form1_Load(object sender, EventArgs e)
{
var t = Task.Factory.StartNew(() => Engine());
t.Start();
}
private void Engine()
{
while (true)
{
Thread.Sleep(1000);
Ticker ltcusd = BtceApi.GetTicker(BtcePair.LtcUsd);
label1.Text = "LTC/USD: " + ltcusd.Last;
}
}
Using async/await, the simplest way of getting an "asynchronous" sort of API is to invoke a new task. It's not great, but it'll make things simpler. I would probably create a new class which basically wrapped all the BtceApi methods in tasks:
public class BtceApiAsync
{
public Task<Ticker> GetTickerAsync(BtcePair pair)
{
return Task.Run(() => BtceApi.GetTicker(pair));
}
// etc
}
Then you can use a timer which fires once per second, which will start off a new task and update the UI appropriately:
// Keep a field of type System.Windows.Forms.Timer
timer = new Timer();
timer.Interval = 1000;
timer.Tick += DisplayTicker;
timer.Start();
...
private async void DisplayTicker(object sender, EventArgs e)
{
Ticker ticker = await BtceApiAsync.GetTickerAsync(BtcePair.LtcUsd);
label1.Text = "LTC/USD: " + ltcusd.Last;
}
Note that this doesn't mean the screen will be updated once per second... there will be a new task started once per second, and as soon as each task completes, the UI will be updated.
The use of await here - from an async method started on the UI thread - means you don't need to worry about using the UI; the whole async method will execute on the UI thread, even though the fetch itself happens in a different thread.
You can try ContinueWith to update the Label at the end of the task. If you want to update it event before the task ends then raise an event which is registered by on the UI thread. The event can then update the label.
I suppose this is Windows Forms. You could do it "old school style" and set the label text on the UI thread, and you can do that by passing delegate to the BeginInvoke or Invoke method.
private void Engine()
{
while (true)
{
Thread.Sleep(1000);
Ticker ltcusd = BtceApi.GetTicker(BtcePair.LtcUsd);
UpdateText("LTC/USD: " + ltcusd.Last);
}
}
private void UpdateText(string text)
{
//Inspect if the method is executing on background thread
if (InvokeRequired)
{
//we are on background thread, use BeginInvoke to pass delegate to the UI thread
BeginInvoke(new Action(()=>UpdateText(text)));
}
else
{
//we are on UI thread, it's ok to change UI
label1.Text = text;
}
}

threads communication

I have a form with text box and button. On click of button I'm creating a thread and invoking it for some operation. once the thread completes the invoked task, I want to update the text box with the result.
any one please assist me how can I achieve this without thread clash.
This is far simpler using .NET 4.0's Task class:
private void button_Click(object sender, EventArgs e)
{
Task.Factory.StartNew( () =>
{
return DoSomeOperation();
}).ContinueWith(t =>
{
var result = t.Result;
this.textBox.Text = result.ToString(); // Set your text box
}, TaskScheduler.FromCurrentSynchronizationContext());
}
If you're using .NET 4.5, you can simplify this further using the new async support:
private async void button_Click(object sender, EventArgs e)
{
var result = await Task.Run( () =>
{
// This runs on a ThreadPool thread
return DoSomeOperation();
});
this.textBox.Text = result.ToString();
}
You need to use Control.Invoke to manipulate your form in it's own thread.
Simply, at the end of the thread operation:
/// ... your code here
string newText = ...
textBox.Invoke((MethodInvoker) delegate {
textBox.Text = newText;
});
The Control.Invoke usage uses the message-queue to hand work to the UI thread, so it is the UI thread that executes the textBox.Text = newText; line.
Use a BackgroundWorker, assign the task to the DoWork event, and update the text box with the RunWorkerCompleted event. Then you can start the task with RunWorkerAsync().
You can use the solutions showed here:
How to update the GUI from another thread in C#?
Next time search a bit before asking.

Running a method with parameters in a thread in c#

I am currently working on a project in C#. I have a method called updateProgress() which has two int parameters (count and totalRows).
If I have call the method by saying updateProgress(count, totalRows) this works fine but I want to run this method within a new thread.
How can I go about doing this, I have looked online and everything looks overly complicated for what I am wanting to do.
Thanks for your help with this
Something like this:
new Thread(delegate () {
updateProgress(count, totalRows);
}).Start();
Be aware that threading actually is quite a complex topic, so if you have troubles understanding the asynchronous APIs available in the .NET Framework, I doubt if you should start using threads in the first place.
Anyway, you have several options:
Spin off a thread by your own (like cdhowie pointed out), which is rather discouraged.
Use the TPL (task parallel library) if you are running on .NET 4. Here is a good introduction.
TaskFactory.StartNew(() => updateProgress(count, totalRows));
Use the ThreadPool if you are running on an older version of .NET.
ThreadPool.QueueUserWorkItem(s => updateProgress(count, totalRows));
Of course there are other ways too, but this are imo the most important ones.
Best Regards,
Oliver Hanappi
This has been almost a year, and my answer will not add anything "new" to what has already been said in other answers.
If someone is using .Net 4.0 or higher, best options would be to use a task and let the framework decide the best, by calling TaskFactory.StartNew(...). For older versions, still it's better to utilize the thread pool by using ThreadPool.QueueUserWorkItem(...).
Now, if still someone wants to use the thread in the basic way (creating new thread) for some reason, then this
new Thread(delegate () {
updateProgress(count, totalRows);
}).Start();
can be written in a little cleaner way, using the lambda expression, like this
new Thread(() => updateProgress(count, totalRows)).Start();
There are different ways to run a method in a different thread, like Thread, BackgroundWorker, ThreadPool or Task. Which one to choose depends of various things.
From the name of the method, it sounds like the method should show some progress in the GUI of your application. If that's the case, you have to run the method on the GUI thread. If you want to call it from another thread, you have to use Dispatcher.Invoke() in WPF and Control.Invoke() in WinForms.
try following
ThreadPool.QueueUserWorkItem((o) => { updateProgress(5, 6); });
Here's a more complex example without anonymous delegates. Look at result in the completed function.
using System;
using System.Threading;
using System.ComponentModel;
class Program
{
static BackgroundWorker _bw;
static void Main()
{
_bw = new BackgroundWorker
{
WorkerReportsProgress = true,
WorkerSupportsCancellation = true
};
_bw.DoWork += bw_DoWork;
_bw.ProgressChanged += bw_ProgressChanged;
_bw.RunWorkerCompleted += bw_RunWorkerCompleted;
_bw.RunWorkerAsync ("Hello to worker");
Console.WriteLine ("Press Enter in the next 5 seconds to cancel");
Console.ReadLine();
if (_bw.IsBusy) _bw.CancelAsync();
Console.ReadLine();
}
static void bw_DoWork (object sender, DoWorkEventArgs e)
{
for (int i = 0; i <= 100; i += 20)
{
if (_bw.CancellationPending) { e.Cancel = true; return; }
_bw.ReportProgress (i);
Thread.Sleep (1000); // Just for the demo... don't go sleeping
} // for real in pooled threads!
e.Result = 123; // This gets passed to RunWorkerCompleted
}
static void bw_RunWorkerCompleted (object sender,
RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
Console.WriteLine ("You canceled!");
else if (e.Error != null)
Console.WriteLine ("Worker exception: " + e.Error.ToString());
else
Console.WriteLine ("Complete: " + e.Result); // from DoWork
}
static void bw_ProgressChanged (object sender,
ProgressChangedEventArgs e)
{
Console.WriteLine ("Reached " + e.ProgressPercentage + "%");
}
}

How do I run a simple bit of code in a new thread?

I have a bit of code that I need to run in a different thread than the GUI as it currently causes the form to freeze whilst the code runs (10 seconds or so).
Assume I have never created a new thread before; what's a simple/basic example of how to do this in C# and using .NET Framework 2.0 or later?
Good place to start reading is Joe Albahari.
If you want to create your own thread, this is as simple as it gets:
using System.Threading;
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
/* run your code here */
Console.WriteLine("Hello, world");
}).Start();
BackgroundWorker seems to be best choice for you.
Here is my minimal example. After you click on the button the background worker will begin working in background thread and also report its progress simultaneously. It will also report after the work completes.
using System.ComponentModel;
...
private void button1_Click(object sender, EventArgs e)
{
BackgroundWorker bw = new BackgroundWorker();
// this allows our worker to report progress during work
bw.WorkerReportsProgress = true;
// what to do in the background thread
bw.DoWork += new DoWorkEventHandler(
delegate(object o, DoWorkEventArgs args)
{
BackgroundWorker b = o as BackgroundWorker;
// do some simple processing for 10 seconds
for (int i = 1; i <= 10; i++)
{
// report the progress in percent
b.ReportProgress(i * 10);
Thread.Sleep(1000);
}
});
// what to do when progress changed (update the progress bar for example)
bw.ProgressChanged += new ProgressChangedEventHandler(
delegate(object o, ProgressChangedEventArgs args)
{
label1.Text = string.Format("{0}% Completed", args.ProgressPercentage);
});
// what to do when worker completes its task (notify the user)
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(
delegate(object o, RunWorkerCompletedEventArgs args)
{
label1.Text = "Finished!";
});
bw.RunWorkerAsync();
}
Note:
I put everything in single method
using C#'s anonymous method for
simplicity but you can always pull
them out to different methods.
It is safe to update GUI within
ProgressChanged or
RunWorkerCompleted handlers.
However, updating GUI from DoWork
will cause
InvalidOperationException.
The ThreadPool.QueueUserWorkItem is pretty ideal for something simple. The only caveat is accessing a control from the other thread.
System.Threading.ThreadPool.QueueUserWorkItem(delegate {
DoSomethingThatDoesntInvolveAControl();
}, null);
Here is another option:
Task.Run(()=>{
//Here is a new thread
});
Quick and dirty, but it will work:
Using at top:
using System.Threading;
simple code:
static void Main( string[] args )
{
Thread t = new Thread( NewThread );
t.Start();
}
static void NewThread()
{
//code goes here
}
I just threw this into a new console application for an exmaple
Try using the BackgroundWorker class. You give it delegates for what to run, and to be notified when work has finished. There is an example on the MSDN page that I linked to.
If you want to get a value:
var someValue;
Thread thread = new Thread(delegate()
{
//Do somthing and set your value
someValue = "Hello World";
});
thread.Start();
while (thread.IsAlive)
Application.DoEvents();
Put that code in a function (the code that can't be executed on the same thread as the GUI), and to trigger that code's execution put the following.
Thread myThread= new Thread(nameOfFunction);
workerThread.Start();
Calling the start function on the thread object will cause the execution of your function call in a new thread.
Here how can use threads with a progressBar , its just for understing how the threads works, in the form there are three progressBar and 4 button:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
Thread t, t2, t3;
private void Form1_Load(object sender, EventArgs e)
{
CheckForIllegalCrossThreadCalls = false;
t = new Thread(birinicBar); //evry thread workes with a new progressBar
t2 = new Thread(ikinciBar);
t3 = new Thread(ucuncuBar);
}
public void birinicBar() //to make progressBar work
{
for (int i = 0; i < 100; i++) {
progressBar1.Value++;
Thread.Sleep(100); // this progressBar gonna work faster
}
}
public void ikinciBar()
{
for (int i = 0; i < 100; i++)
{
progressBar2.Value++;
Thread.Sleep(200);
}
}
public void ucuncuBar()
{
for (int i = 0; i < 100; i++)
{
progressBar3.Value++;
Thread.Sleep(300);
}
}
private void button1_Click(object sender, EventArgs e) //that button to start the threads
{
t.Start();
t2.Start(); t3.Start();
}
private void button4_Click(object sender, EventArgs e)//that button to stup the threads with the progressBar
{
t.Suspend();
t2.Suspend();
t3.Suspend();
}
private void button2_Click(object sender, EventArgs e)// that is for contuniue after stuping
{
t.Resume();
t2.Resume();
t3.Resume();
}
private void button3_Click(object sender, EventArgs e) // finally with that button you can remove all of the threads
{
t.Abort();
t2.Abort();
t3.Abort();
}
}
If you are going to use the raw Thread object then you need to set IsBackground to true at a minimum and you should also set the Threading Apartment model (probably STA).
public static void DoWork()
{
// do some work
}
public static void StartWorker()
{
Thread worker = new Thread(DoWork);
worker.IsBackground = true;
worker.SetApartmentState(System.Threading.ApartmentState.STA);
worker.Start()
}
I would recommend the BackgroundWorker class if you need UI interaction.
// following declaration of delegate ,,,
public delegate long GetEnergyUsageDelegate(DateTime lastRunTime,
DateTime procDateTime);
// following inside of some client method
GetEnergyUsageDelegate nrgDel = GetEnergyUsage;
IAsyncResult aR = nrgDel.BeginInvoke(lastRunTime, procDT, null, null);
while (!aR.IsCompleted) Thread.Sleep(500);
int usageCnt = nrgDel.EndInvoke(aR);
Charles your code(above) is not correct. You do not need to spin wait for completion. EndInvoke will block until the WaitHandle is signaled.
If you want to block until completion you simply need to
nrgDel.EndInvoke(nrgDel.BeginInvoke(lastRuntime,procDT,null,null));
or alternatively
ar.AsyncWaitHandle.WaitOne();
But what is the point of issuing anyc calls if you block? You might as well just use a synchronous call. A better bet would be to not block and pass in a lambda for cleanup:
nrgDel.BeginInvoke(lastRuntime,procDT,(ar)=> {ar.EndInvoke(ar);},null);
One thing to keep in mind is that you must call EndInvoke. A lot of people forget this and end up leaking the WaitHandle as most async implementations release the waithandle in EndInvoke.
another option, that uses delegates and the Thread Pool...
assuming 'GetEnergyUsage' is a method that takes a DateTime and another DateTime as input arguments, and returns an Int...
// following declaration of delegate ,,,
public delegate long GetEnergyUsageDelegate(DateTime lastRunTime,
DateTime procDateTime);
// following inside of some client method
GetEnergyUsageDelegate nrgDel = GetEnergyUsage;
IAsyncResult aR = nrgDel.BeginInvoke(lastRunTime, procDT, null, null);
while (!aR.IsCompleted) Thread.Sleep(500);
int usageCnt = nrgDel.EndInvoke(aR);
There are many ways of running separate threads in .Net, each has different behaviors. Do you need to continue running the thread after the GUI quits? Do you need to pass information between the thread and GUI? Does the thread need to update the GUI? Should the thread do one task then quit, or should it continue running? The answers to these questions will tell you which method to use.
There is a good async method article at the Code Project web site that describes the various methods and provides sample code.
Note this article was written before the async/await pattern and Task Parallel Library were introduced into .NET.
How to: Use a Background Thread to Search for Files
You have to be very carefull with access from other threads to GUI specific stuff (it is common for many GUI toolkits). If you want to update something in GUI from processing thread check this answer that I think is useful for WinForms. For WPF see this (it shows how to touch component in UpdateProgress() method so it will work from other threads, but actually I don't like it is not doing CheckAccess() before doing BeginInvoke through Dispathcer, see and search for CheckAccess in it)
Was looking .NET specific book on threading and found this one (free downloadable). See http://www.albahari.com/threading/ for more details about it.
I believe you will find what you need to launch execution as new thread in first 20 pages and it has many more (not sure about GUI specific snippets I mean strictly specific to threading). Would be glad to hear what community thinks about this work 'cause I'm reading this one. For now looked pretty neat for me (for showing .NET specific methods and types for threading). Also it covers .NET 2.0 (and not ancient 1.1) what I really appreciate.
I'd recommend looking at Jeff Richter's Power Threading Library and specifically the IAsyncEnumerator. Take a look at the video on Charlie Calvert's blog where Richter goes over it for a good overview.
Don't be put off by the name because it makes asynchronous programming tasks easier to code.

Categories

Resources