This question already has an answer here:
Label won't change color until after code is finished executing
(1 answer)
Closed 8 years ago.
I have a problem with my winform app in C#.
In program, i have a label as statusbar and a method like this:
private void btnProcess_Click(object sender, EventArgs e)
{
lblStatus.Text = "Please wait...";
/*
Code here
*/
}
my code process taking a few second but after processing the code, text of label will change and i want it happening before that.
Note: I am an amateur in programming and i cant understand english very well, please explain your solution simply. thank you.
You may be able to hack this using a repaint event by calling Update or Refresh, but the real solution is using a BackgroundWorker for longer operations.
This is not easy stuff, you should find a tutorial for it in a language you understand perfectly.
In winform application (but also in all GUI application) it's not recommended execute long task in the GUI thread. For solving your problem you must use Thread(here you can find the complete mdsn reference).
If you want update the Label from another Thread you' ll do a Cross threading operation. For more information take a look to this question
All the code is always ran and completed before any changes are made to the UI. This is just the basic logic of WinForms and WPF.
You can use "BackgroundWorker", so the longer code is run on another thread. This way you can freely edit the UI-elements while the longer code is still running.
If you are using .Net 4.5, you can use await and async rather than BackgroundWorker.
You would create an async method that returns a Task, and inside that method use Task.Run() to start the background work.
Here's an example. You'd do all the slow work in the lambda passed to Task.Run() where I've commented "Do all your slow work here":
private async void btnProcess_Click(object sender, EventArgs e)
{
lblStatus.Text = "Please wait...";
await doSomeWorkAsynchronously();
lblStatus.Text = "Work completed";
}
private async Task doSomeWorkAsynchronously()
{
await Task.Run(()=>
{
// Do all your slow work here.
Thread.Sleep(5000); // Simulate slow work.
});
}
I think this is a bit easier than using BackgroundWorker.
Note that if all your "slow" methods were already async (e.g. if you are using asynchronous file I/O) then you might just be able to await each of your async operations rather than having to create your own task via Task.Run().
You can also return a value from the background task. Suppose you wanted to return a string with which to update the label when the background task had completed. You could do that as follows:
private async void btnProcess_Click(object sender, EventArgs e)
{
lblStatus.Text = "Please wait...";
lblStatus.Text = await doSomeWorkAsynchronously();
}
private async Task<string> doSomeWorkAsynchronously()
{
return await Task.Run(()=>
{
// Do all your slow work here.
Thread.Sleep(5000); // Simulate slow work.
return "The task completed.";
});
}
Related
public MainPage()
{
Method_1();
Method_2();
Method_3();
Method_4();
Method_5();
Method_6();
}
I am writing a Windows Phone 8.1 App (WINRT XAML). How to make these methods execute at a time from constructor? What I mean to ask is about multithreading, i want these methods to get executed sidebyside and not one after another.
Does this effect loading of application? will app load fast/slow?
First off, you don't want to execute those methods in the constructor if they are long running methods. Wait until the page is loaded:
private async void Page_Loaded(object sender, RoutedEventArgs e)
{
Task m1task = Method_1();
Task m2task = Method_2();
Task m3task = Method_3();
Task all = Task.WhenAll(m1Task, m2Task, m3Task);
await all;
}
The code will load off these operations to another thread and as long as your methods are properly implemented your UI will stay responsive (so don't use wait() for instance).
This is what a sample method could look like:
private async Task Method_1() {
// Long running operation goes here
}
If you have some heavy computations to do, wrap them into Task.Run(() => { // Code });It's really essential that you're aware of the concepts of asynchronous programming. You might want to read on here:
Do you have to put Task.Run in a method to make it async?
await vs Task.Wait - Deadlock?
When correctly use Task.Run and when just async-await
But seriously, you're writing that your methods are not UI related. You might be better off running those somewhere else (e.g. in your ViewModels or even in a background task / service).
Mark the methods as Async with return type Task.
eg. public async Task method1(){}
You won't be able to fire any UI activities from them, but they'll run outside of the main thread.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I want to control some UI elements by a thread and the others by different thread in WP8.
Is there any way to make Muulti UI thread like this? Help me.
In order to update your UI from multiple threads, you can use the Dispatcher
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
// Code to modify your UI
}
As I stated in my comment, I think you're thinking about the problem the wrong way. What you want is not actually to have more than one GUI thread, you just want to do the work on some other thread. Let me illustrate this with some pseudo code (untested):
// API method with Thread.Sleep as requested
public static int GetAnswer() {
Thread.Sleep(5000);
return 42;
}
// Code assumes to be inside some kind of "Window" class where there is a Dispatcher
public void SomeButton_OnClick(object sender, EventArgs e) {
Task.Run(() => {
int answer = GetAnswer();
Dispatcher.BeginInvoke(() => {
MyLabel.Text = answer;
});
});
}
And now for the explanation:
What happens here is that there is some button, that when clicked calls a method (GetAnswer) that takes a long time (5 seconds). If that method is called on the GUI thread, the GUI will hang for 5 seconds (not a good thing), so what we instead do is call GetAnswer on another thread (using Task.Run, other possible ways to do this is with queueing on the threadpool manually, but Task.Run has a simple name and is easier to remember when you don't have Visual Studio handy to help you). The thread created by the call to Task.Run then starts working on the answer, and after 5 seconds it completes. However, since it's running on a background thread, you can't update the GUI, so therefore (with help of the Dispatcher) it tells the GUI-thread to update the the text of MyLabel at first chance.
This will give you the ability to call slow methods (either because they do CPU bound work, or they sleep) and then use the result in the GUI.
[Edit]
I read your comment about loading content from the internet, and what you probably want to check out is using async API's instead of synchronous ones. Thus you would be able to write code like this without it blocking the UI at all:
public async void SomeButton_OnClick(object sender, EventArgs e) {
// Because we use await here, the GUI thread will not be blocked
var data = await DownloadFromSomewhereAsync();
// Once the resource is done downloaded, the rest of the method will run on the UI thread
MyLabel.Text = data;
}
Note ofcause, that in order to use async methods your API needs to support it. Or you could simplify the code I posted in my previous example to this:
// API method with Thread.Sleep as requested
public static int GetAnswer() {
Thread.Sleep(5000);
return 42;
}
public async void SomeButton_OnClick(object sender, EventArgs e) {
int answer;
await Task.Run(() => {
answer = GetAnswer();
});
MyLabel.Text = answer;
}
This is because Task.Run returns a Task that can be awaited.
I'm working on a Windows 8.1 store app in which the user can save text to a file.
I've been trying to understand how to best use async and await.
This is what I've come up with:
private async void userText_KeyDown(object sender, KeyRoutedEventArgs e)
{
if (e.Key == Windows.System.VirtualKey.Enter)
{
if (addUserImput)
{
userStringlist.Add(userBox.Text);
userBox.Text = "";
addUserImput = false;
}
await WriteToFileAsync();
addUserImput = true;
}
}
And the async-method looks like this:
private async Task WriteToFileAsync()
{
string name = "userStrings.txt";
var option = CreationCollisionOption.ReplaceExisting;
var folder = Windows.Storage.ApplicationData.Current.LocalFolder;
var file = await folder.CreateFileAsync(name, option);
await Windows.Storage.FileIO.WriteLinesAsync(file, userStringlist);
}
As soon as WriteToFileAsync reaches the await-keyword the execution will start over. In order to prevent duplicates in my list I had to add the if-statement.
It just strikes me as odd. I'm still new to this, so I might've missed something. Why does the keydown event resume from the top, doing work that has already been done?
My "workaround" works, I just don't get the logic behind the event's behaviour.
Yes, that's how asynchronous solutions work. When you hit your first actually asynchronous operation (in this case, CreateFileAsync) the method returns to its caller, which returns to its caller, and it eventually works it's way out of the entire method and back up to your application's message loop. It then continues on processing other UI messages. Some of those messages may be key down events (and they could end up being run before your asynchronous operation is completed). Other events could be things like paint events or mouse click events that lets your form do whatever it needs to interact with the user. This is what prevents it from freezing.
What you want to do is to prevent the given section of code that you have from being run concurrently. If this weren't asynchronous this is something that you would generally solve using the lock keyword, but that isn't an option for an asynchronous method. What you need is some method of preventing access to the code until any other executions of that code block finish. Fortunately there are tools available to do this. You could use a boolean, as you are, but this is somewhat fragile and fairly easy to make a mistake with as the complexity of the application grows. A Semaphore is specifically designed for this task:
private SemaphoreSlim semaphore = new SemaphoreSlim(1);
private async void Bar()
{
try
{
await semaphore.WaitAsync();
//do stuff
}
finally
{
semaphore.Release();
}
}
The SemaphoreSlim class has a WaitAsync method specifically designed for use in asynchronous methods, such as yours. You can wait until the semaphore is free, do your code, and then ensure that you release the semaphore when done so that other code can then move into the code block.
You may need to use handled = true in this case . check if http://msdn.microsoft.com/en-us/library/system.windows.forms.keyeventargs.handled(v=vs.110).aspx works
After looking around on both Async/Await and Threading, I'm still unsure of the right way to apply it to my situation. No matter the variation that I try my UI still hangs because I don't seem to be calling my desired function asynchronously, additionally, I may in fact need threading for my solution.
What I'm trying to do: I have a WPF application on which there is a button that I would like to start an operation that still allows interaction with the program, through UI or otherwise. Once a condition is met that is determined outside of this function, the function should end. To me this sounds fairly standard but I have a feeling I'm misunderstanding something and I've implemented it incorrectly.
What I have right now:
private async void start_button_Click(object sender, RoutedEventArgs e)
{
await StaticClass.MyFunction();
}
private void stop_button_Click(object sender, RoutedEventArgs e)
{
StaticClass.stopFlag = true;
}
public static Task<int> myFunction()
{
//Stuff Happens
while(StaticClass.stopFlag == false)
//Do Stuff
//Stuff Happens
return Task.FromResult(1) //I know this is bad, part of the reason I'm asking
}
I was hoping for some guidance on if I'm approaching this the right way and any insight on what I'm doing wrong.
You've definitely implemented it incorrectly. You're returning a Task<int>, but only once all the work has already been done.
It seems to me that you should probably just have a synchronous method:
private static void MyFunction()
{
// Loop in here
}
Then start a task for it like this:
Task task = Task.Run((Action) MyFunction);
You can then await that task if you want - although in the example you've given, there's no point in doing so, as you're not doing anything after the await anyway.
I'd also agree with Reed that using a CancellationToken would be cleaner than a static flag somewhere else.
You did misunderstand.
public static Task<int> myFunction()
{
//Stuff Happens
while(StaticClass.stopFlag == false)
//Do Stuff
//Stuff Happens
return Task.FromResult(1) //I know this is bad, part of the reason I'm asking
}
All of that code still happens in the intial await StaticClass.MyFunction(); call, it never returns control to the caller. What you need to do is put the loop portion in to a separate thread.
public static async Task myFunction()
{
//Stuff Happens on the original UI thread
await Task.Run(() => //This code runs on a new thread, control is returned to the caller on the UI thread.
{
while(StaticClass.stopFlag == false)
//Do Stuff
});
//Stuff Happens on the original UI thread after the loop exits.
}
Instead of trying to use a bool for this, you should consider using the managed cancellation framework built into the framework.
Basically, you'd build a CancellationTokenSource, and pass a CancellationToken to your method which could be used to handle cancellation.
Finally, your current method will never get off the UI thread. You'd need to use Task.Run or similar to move the method to the ThreadPool if you don't want to block the UI.
As an alternative, you could look into using BackgroundWorker class to do the job, your UI will stay interactive.
I have some code that works as follows:
App.xaml calls a SetUp() method which populates a local collection using async calls and exposes the collection as a public property.
That's all good.
Now I make an instance of the first page in my Silverlight app like so
private void Application_Startup(object sender, StartupEventArgs e)
{
this.RootVisual = new Summary();
}
In the constructor of Summary() I expect those async calls to have been complete and my collection to be filled but the async calls have not yet complete. Even if I do a Thread.Sleep(100000....) before i make an instance on Summary() this is the case
And the thing is that until the constructor of Summary() is exited and the UI displayed to the user my async calls do not get kicked off!
What!!!
Is there anything I can do about that or is that just the way asyn calls work i.e. they wait until the current until of work finished before firing?
This is how I work round this situation (I'll use simple string download as an example):-
private void Application_Startup(object sender, StartupEventArgs e)
{
WebClient web = new WebClient();
web.DownloadStringCompleted += (s, args) =>
{
// Do stuff with args.Result);
this.RootVisual = new Summary();
};
web.DownloadStringAsync(new Uri("SomeUrl.txt", UriKind.Relative));
}
Note that the construction of Summary and the assignment to RootVisual are defered until the asynchronous download is complete.
Silverlight was specifically designed to not have any blocking operations -- that's why you have to do async in the first place. What you really have to do is make your app run properly while waiting for the async completion handler to execute.
This is by design. The alternative would be that the user has to wait longer before he sees anything at all.
If you really want to prevent showing an incomplete summery then first shown another page with 'waiting' or a progress bar. Fire the async events from that page or its parent. Then show the Summary when the async call returns.
To deal with an incomplete Summary you might want to use ICommand
I know this is an old thread, but for all following reader i want to provide my experience with a similar problem. If i understood you correctly - the reason why your async calls do not complete is because you block the main thread. I ran into the same problem, if you block the main thread none of the other threads continue. The solution was to do the async calls inside a backgroundworker and show, like pauldendulk said, a waiting - page. Use Debug.WriteLine() to monitor the process in the output.