I am working on a user interface in C#.
When the program is running (this process takes several minutes...), before run, I want a message is displayed and after run, the message will disappear automatically.
My aim is to give an information message like 'Running, please wait' to the user.
I tried the code shown below:
(formMsgWait has only a label 'Running, please wait')
private void btnExit_Click(object sender, EventArgs e)
{
using (formMsgWait fMsgWait = new formMsgExit())
{
fMsgWait.Show();
System.Windows.Forms.Application.DoEvents();
...statement 1
...statement 2
...
}
}
When run to System.Windows.Forms.Application.DoEvents(); the program doesn't run continue, so all of the statements below doesn't do (...statement 1, ...statement 2, ...), formMsgWait doesn't close.
Is there anyway to do that?
Any tips on these will be great help.
You're blocking the current thread. According to http://msdn.microsoft.com/en-us/library/system.windows.forms.application.doevents.aspx
Calling this method causes the current thread to be suspended while
all waiting window messages are processed. If a message causes an
event to be triggered, then other areas of your application code may
execute. This can cause your application to exhibit unexpected
behaviors that are difficult to debug. If you perform operations or
computations that take a long time, it is often preferable to perform
those operations on a new thread. For more information about
asynchronous programming, see Asynchronous Programming Overview.
So that's what you should actually be doing here: start all of your actual work on a separate thread, preferably using async. For example:
public async Task<bool> DoTheWorkAsync()
{
formMsgWait f = new formMsgWait();
f.Show();
bool finished = await Task.Run(() => DoTheWork());
f.Close();
return finished;
}
private bool DoTheWork()
{
... work
return true;
}
Oh. I think you can use Dialog Window. Visit this link to refer:
https://msdn.microsoft.com/en-us/library/c7ykbedk(v=vs.110).aspx
Related
In app.xaml.cs
private void Application_Closing(object sender, ClosingEventArgs e)
{
A.onEndApp();
}
In class A
async public static void onEndApp()
{
string temp=await doSomething();
//code here
}
I have a problem,when I close an app,and then onEndApp() method is run,
when doSomething() run complete and {//code here} is not run,but if I put A.onEndApp() in
another method it run normaly,for example Application_Launching() method,it will be run
{//code here}
I think when app is running it no problem,but when app is closing it run await complete and then stop,I want to run complete method when I close app in async.
After Application_Closing is executed (synchronously), the OS will terminate the process. There might be a short delay before it does so, and that might be enough for you to finish writing to isolated storage, or it might not in which case you'll end up having corrupted state
I'll just take a direct quote from "Beware the perils of async/await in application lifecycle event handlers (in fact in any event handlers)" on Andy Wigley's blog.
Calling async code from Application_Deactivated or Application_Closing
The guidance here is “don’t'”. If you write your apps carefully, you can be saving changes to persistent data as you go along, so you shouldn’t have anything to do in the application lifecycle events.
If you must, you can try doing something like this:
SomeAsyncMethod().AsTask().Wait()
If the operation completes within the timeout period AND it doesn’t deadlock due to needing
to pump the UI thread, it will work… but don’t count on it.
Try this:
private void Application_Closing(object sender, ClosingEventArgs e)
{
var task = A.onEndApp();
task.Wait();
}
async public static Task onEndApp()
{
string temp = await doSomething();
//code here
}
Otherwise, you're effectively just spinning off a thread that will never get a chance to run to completion, because the application is closing out from underneath it, and the thread will get terminated before it can run.
This question already has answers here:
WebBrowser Control in a new thread
(4 answers)
Closed 9 years ago.
Basically I have a form with a button, when the button is pressed it creates an instance of a class that runs a Thread. When the thread is done, it automatically calls Thread.Abort().
The code I currently have comes down to this:
Button:
private void Buttonclick(object sender, EventArgs e)
{
MyClass c = new MyClass()
c.Do_your_thing();
}
Class:
public class MyClass
{
Thread t;
public void Do_your_thing()
{
t = new Thread(Running_code);
t.Start();
}
private void Running_code()
{
//Perform code here
t.Abort();
}
}
When I click the button once, everything works. But when I press the button again, nothing happens.
When I don't use t.Abort() everything works. But not using t.Abort() will cause memory leaks and the program won't close properly (the thread is never closed, therefor the process will stay alive).
Can anyone explain me what is going on? And how can I fix it?
EDIT: as per request I am posting some actual code
public class MyClass
{
public void Test()
{
t = new Thread(() =>
{
wb.DocumentCompleted += get_part;
wb.Navigate("http://www.google.com");
Application.Run();
});
t.SetApartmentState(ApartmentState.STA);
t.Start();
}
public void get_part(object sender, WebBrowserDocumentCompletedEventArgs e)
{
var br = sender as WebBrowser;
string url = e.Url.ToString();
//Here is some code that compares the url to surten predefined url. When there is a match, it should run some code and then go to a new url
if(url == string_final_url)
{
//Finally at the url I want, open it in a new Internet Explorer Window
Process proc = Process.Start("IExplore.exe", url);
}
}
}
This is a fraction of a little webscraper program. It navigates to a webpage that needs some login info. When I reached the page I actually want to be, he should open it in a new Internet Explorer.
When I call this code and close the form, it's still visible in the process tree. And when I click the button multiple times, the memory used keeps getting higher, which I suspected to be some sort of memory leak.
Firstly, don't use Thread.Abort(), ever. See Is this thread.abort() normal and safe? for more details on why.
There are many warnings all over the net about using Thread.Abort(). I would recommend avoiding it unless it's really needed, which in this case, I don't think it is. You'd be better off just implementing a one-shot timer, with maybe a half-second timeout, and resetting it on each keystroke. This way your expensive operation would only occur after a half-second or more (or whatever length you choose) of user inactivity.
Instead of using abort you can use the Join() Method. This method blocks the calling thread until a thread terminates.
An example of it use is
Thread t1 = new Thread(() =>
{
Thread.Sleep(4000);
Console.WriteLine("t1 is ending.");
});
t1.Start();
Thread t2 = new Thread(() =>
{
Thread.Sleep(1000);
Console.WriteLine("t2 is ending.");
});
t2.Start();
t1.Join();
Console.WriteLine("t1.Join() returned.");
t2.Join();
Console.WriteLine("t2.Join() returned.");
I hope this helps.
Edit. To address your comments; The call to Join() is what de-allocates the thread. You don't have to do anything else. Just make sure that the threads clean up any resources they might be using before they exit.
That said, I would urge you to look into using the thread pool or the Task Parallel Library (TPL) rather than explicitly managing threads. They're easier to use, and handle this kind of thing much more smoothly.
Are you able to utilize .net 4 + if so you can use the TPL which would greatly simpify this as
public class MyClass
{
public void Do_your_thing()
{
// for async execution
Task.Factory.StartNew(Running_code);
// for synchronous execution
// CAUTION !! If invoked from UI thread this will freeze the GUI until Running_code is returned.
//Task.Factory.StartNew(Running_code).Wait();
}
private void Running_code()
{
Thread.Sleep( 2000 );
Debug.WriteLine( "Something was done" );
}
}
Moreover if the Running_Code method was doing something IO bound the TPL can utilize the IO completion ports and the operation may be completely threadless.
EDIT:
Have a look at this SO thread. WebBrowser Control in a new thread.
Apparently webbrowser control does not play well with non UI threads.
So I'm working on a windows 8 application with some asynchronous methods.
In one particular place I need the aplication to wait for the async method to finish, but it doesn't seem it sends the EventHandle it's state.
Here are the methods that need to work together:
public class Film : Page
private User loggedinUser = new User();
private EventWaitHandle handle = new AutoResetEvent(false);
private dynamic parameters;
protected override void OnNavigatedTo(NavigationEventArgs e)
{
this.parameters = e.Parameter;
LoadFacebookData(parameters);
handle.WaitOne();
LoadUserMovies(loggedinUser.UserName);
}
private async void LoadFacebookData(dynamic parameter)
{
//async code that gets info from facebook whichs determines what user is logged in
handle.Set();
}
private void LoadUserMovies(string username)
{
// irrelevant code
}
the moment the code hits the handle.WaitOne() bit, it stops working completely
In short you are not supposed to use async and wait on something. The standard mistake is to wait on the task returned (deadlock). You did a variation on this: You created an event and waited on it (also deadlock).
Solution: Either embrace async-await or don't do async at all. Can't do both in a mixed style (generally).
If await is available to you, this is a good start:
await LoadFacebookData(parameters);
Get rid of the event.
I suggest you to use the
await LoadFacebookData(parameters);
code line to get the execution continue on the same thread it was started once your async operation finishes.
As far as I can see, there is nothing wrong with the code you have posted. This leads me to believe that the problem is in the code you have commented away. The problem is probably that your code-execution never reaches the line
handle.Set();
This can be because of an exception, or your async code simply never completes. To "deal" with the possibility of an exception, you should probably use the builtin Wait-method of the Task-object, rather than your own EventWaitHandle.
You can remove the EventWaitHandle as a whole, and simply do:
LoadFacebookData(parameters).Wait();
This will propagate any exceptions that occur in the thread within.
Suppose a lot of stuff is happening on the main GUI thread (data flowing in, user actions, etc.). Suppose we would like to create a form and show it.
Could there be a performance boost if we use Application.Run(Form) as opposed to Form.Show()? Is there a better way to do this? Please explain why or why not.
Do not use Application.Run() unless you know what it does. And, once you know what it does, you'll know why you shouldn't use it except at the beginning of the program.
Application.Run starts a message pump. This is the heart of any GUI program, and what enables the window to recieve messages, which allows it to fire events and do stuff. You cannot have two message pumps, as that doesn't make any sense.
(Yes, I know that you can have two message pumps, but why would you ever want to? It's hard enough having one pump!)
As to your real question (how do I not do stuff on my GUI thread), that's a bit more complicated. The simplest answer is "use threads". since I don't know the particulars of your situation, I can only give some general advice:
Do not try to manipulate controls from other threads. At best, it won't work. At worst, it will set your house on fire (okay, maybe not that bad. But, don't do it.). Instead, you need to Invoke methods. An example will be provided below.
Do not run long running processes on your GUI thread. Short things are okay, but anything that might take longer than half a second are probably best offloaded to another thread.
Use events to communicate from your Worker thread back to your GUI thread.
Here is an example of how to run a worker thread:
delegate void VoidDelegate();
List<int> results;
bool cancelWork = false;
void DoWork() {
int calc;
results = new List<int>();
for(int i = int.MinValue ; i < int.MaxValue; i+=10) {
if(cancelWork) break;
results.Add(i);
}
this.Invoke(new VoidDelegate(WorkFinished));
}
void Button1_Click(object sender, EventArgs e) {
button1.Enabled = false;
button2.Enabled = true;
cancelWork = false;
Thread t = new Thread(DoWork);
t.Start();
}
void Button2_Click(object sender, EventArgs e) {
button2.Enabled = false;
cancelWork = true;
}
void WorkFinished() {
button1.Enabled = true;
button2.Enabled = false;
textBox1.Text = results.Count.ToString();
}
Obviously, this is a contrived example, however it serves my purpose.
This hypothetical form contains two buttons, button1 ("Run") and button2 ("Cancel"), and a text box, textbox1. button2 should start out disabled (Enabled = false).
While the worker thread it running, the user can interact with any other controls, including the "Cancel" button (button2 in my example). Once it finishes, it Invokes the WorkFinished function, which displays the results (and otherwise cleans up state).
If you're referring to something that is not your app's main form then the answer would be no. Application.Run() initializes the main message loop and should be called just once when the application starts. All other forms shown during the lifetime of the app should be Form.Show or equivalent.
You can call Application.Run from another thread, but then you'll have two UI threads you need to synchronize anyway. You can't just pass stuff around without ensuring that you won't get into a contention situation.
Lets say I have a component called Tasking (that I cannot modify) which exposes a method “DoTask” that does some possibly lengthy calculations and returns the result in via an event TaskCompleted. Normally this is called in a windows form that the user closes after she gets the results.
In my particular scenario I need to associate some data (a database record) with the data returned in TaskCompleted and use that to update the database record.
I’ve investigated the use of AutoResetEvent to notify when the event is handled. The problem with that is AutoResetEvent.WaitOne() will block and the event handler will never get called. Normally AutoResetEvents is called be a separate thread, so I guess that means that the event handler is on the same thread as the method that calls.
Essentially I want to turn an asynchronous call, where the results are returned via an event, into a synchronous call (ie call DoSyncTask from another class) by blocking until the event is handled and the results placed in a location accessible to both the event handler and the method that called the method that started the async call.
public class SyncTask
{
TaskCompletedEventArgs data;
AutoResetEvent taskDone;
public SyncTask()
{
taskDone = new AutoResetEvent(false);
}
public string DoSyncTask(int latitude, int longitude)
{
Task t = new Task();
t.Completed = new TaskCompletedEventHandler(TaskCompleted);
t.DoTask(latitude, longitude);
taskDone.WaitOne(); // but something more like Application.DoEvents(); in WinForms.
taskDone.Reset();
return data.Street;
}
private void TaskCompleted(object sender, TaskCompletedEventArgs e)
{
data = e;
taskDone.Set(); //or some other mechanism to signal to DoSyncTask that the work is complete.
}
}
In a Windows App the following works correctly.
public class SyncTask
{
TaskCompletedEventArgs data;
public SyncTask()
{
taskDone = new AutoResetEvent(false);
}
public string DoSyncTask(int latitude, int longitude)
{
Task t = new Task();
t.Completed = new TaskCompletedEventHandler(TaskCompleted);
t.DoTask(latitude, longitude);
while (data == null) Application.DoEvents();
return data.Street;
}
private void TaskCompleted(object sender, TaskCompletedEventArgs e)
{
data = e;
}
}
I just need to replicate that behaviour in a window service, where Application.Run isn’t called and the ApplicationContext object isn’t available.
I've had some trouble lately with making asynchronous calls and events at threads and returning them to the main thread.
I used SynchronizationContext to keep track of things. The (pseudo)code below shows what is working for me at the moment.
SynchronizationContext context;
void start()
{
//First store the current context
//to call back to it later
context = SynchronizationContext.Current;
//Start a thread and make it call
//the async method, for example:
Proxy.BeginCodeLookup(aVariable,
new AsyncCallback(LookupResult),
AsyncState);
//Now continue with what you were doing
//and let the lookup finish
}
void LookupResult(IAsyncResult result)
{
//when the async function is finished
//this method is called. It's on
//the same thread as the the caller,
//BeginCodeLookup in this case.
result.AsyncWaitHandle.WaitOne();
var LookupResult= Proxy.EndCodeLookup(result);
//The SynchronizationContext.Send method
//performs a callback to the thread of the
//context, in this case the main thread
context.Send(new SendOrPostCallback(OnLookupCompleted),
result.AsyncState);
}
void OnLookupCompleted(object state)
{
//now this code will be executed on the
//main thread.
}
I hope this helps, as it fixed the problem for me.
Maybe you could get DoSyncTask to start a timer object that checks for the value of your data variable at some appropriate interval. Once data has a value, you could then have another event fire to tell you that data now has a value (and shut the timer off of course).
Pretty ugly hack, but it could work... in theory.
Sorry, that's the best I can come up with half asleep. Time for bed...
I worked out a solution to the async to sync problem, at least using all .NET classes.
Link
It still doesn't work with COM. I suspect because of STA threading. The Event raised by the .NET component that hosts the COM OCX is never handled by my worker thread, so I get a deadlock on WaitOne().
someone else may appreciate the solution though :)
If Task is a WinForms component, it might be very aware of threading issues and Invoke the event handler on the main thread -- which seems to be what you're seeing.
So, it might be that it relies on a message pump happening or something. Application.Run has overloads that are for non-GUI apps. You might consider getting a thread to startup and pump to see if that fixes the issue.
I'd also recommend using Reflector to get a look at the source code of the component to figure out what it's doing.
You've almost got it. You need the DoTask method to run on a different thread so the WaitOne call won't prevent work from being done. Something like this:
Action<int, int> doTaskAction = t.DoTask;
doTaskAction.BeginInvoke(latitude, longitude, cb => doTaskAction.EndInvoke(cb), null);
taskDone.WaitOne();
My comment on Scott W's answer seems a little cryptic after I re-read it. So let me be more explicit:
while( !done )
{
taskDone.WaitOne( 200 );
Application.DoEvents();
}
The WaitOne( 200 ) will cause it to return control to your UI thread 5 times per second (you can adjust this as you wish). The DoEvents() call will flush the windows event queue (the one that handles all windows event handling like painting, etc.). Add two members to your class (one bool flag "done" in this example, and one return data "street" in your example).
That is the simplest way to get what you want done. (I have very similar code in an app of my own, so I know it works)
Your code is almost right... I just changed
t.DoTask(latitude, longitude);
for
new Thread(() => t.DoTask(latitude, longitude)).Start();
TaskCompleted will be executed in the same thread as DoTask does. This should work.