I have created an application in windows form. Once I submit the application, the application get processed. I have created a class library which process the application and move the submitted application to different workflows. For this I have called the Class library from the click event of the Submit button. Everything is working fine, but the only problem is that once I submit the application and it calls the class library, it takes some time as it processes it. I want that the application should get closed and it calls the library method asynchronously. Below is the code:
private void OnPASubmit_Click(object sender, EventArgs e)
{
if ((ApplAcct.AcctID == 0) || CheckForChanges())
{
UIHelper.ShowMessage("Please Save Application first");
return;
}
try
{
if (!AOTHelper.ValidateCheckOut(ApplAcct.AcctID))
{
return;
}
WorkflowTask.PutAccountWorkflowTask(ApplAcct.AcctID, AOTHelper.FindAcctGUID(Main.objAccountGUID, Acct.AcctID), Environment.UserName, 2);
AOTHelper.checkInAccount(ApplAcct.AcctID);
AOTHelper.AccountToProcess(Acct.AcctID);
UIHelper.ShowMessage("Application has been submitted for processing.");
this.Close();
}
catch (Exception ex)
{
AOTHelper.WriteLog(ex, "Can not submit application for processing ");
}
// ...
}
The AotHelper.AccountToProcess(Acct.AcctID), method calls the class library and I want to do this with the help of Asunchronous calling so that the application doesn't have to wait for processing once it get submitted.
How will I do it. Please help!
Multiple ways to run asynchronous, such as TPL, starting your own thread (and in the 4.5 framework await), but for winforms perhaps the easiest way is to add a BackGroundWorker component. You can just drag/drop one from the toolbox on your designer.
Double clicking the added component, automatically creates a method that catches the DoWork event of the backgroundworker, you can place your code there. Then in the submit button you only have to call
backgroundWorker.RunWorkerAsync();
Then you should use BackgroundWorker class.
You can use BackgroundWorker thread...
BackgroundWorker makes threads easy to implement in Windows Forms. Intensive tasks need to be done on another thread so that the UI doesn't freeze. It is necessary to post messages and update the user interface when the task is done.
When you use the BackgroundWorker class, you can indicate operation progress, completion, and cancellation in the user interface. For example, you can check whether the background operation is completed or canceled and display a message to the user.
Read a simple tutorial
Here is a good example:
http://www.ricky-dev.com/2012/05/throttled-processing-of-multiple-asynchronous-tasks/
Several ways. You can start a background worker thread that calls the process and just ends when it's done.
You could create a delegate and use the BeginInvoke.
You could send a message that a listener in a service picks up on a depatches a process to run it.
Lots of ways to skin that cat.
Here is an old but useful MSDN ref http://msdn.microsoft.com/en-us/magazine/cc301332.aspx
You simply need to start it on a separate thread. For instance:
Thread thread = new Thread(new ParameterizedThreadStart(AOTHelper.AccountToProcess));
thread.Start(Acct.AcctID);
If you are going to be starting many threads at the same time, though, you should use a thread pool, instead.
You need to be careful, though. The method you call on the separate thread cannot do anything with the UI or it will throw an exception. If it needs to do something to the UI, it will need a reference to a form or control so it can call that object's Invoke method to get back on the UI thread. Also, since it is happening asynchronously, you will no longer be able to show that message box immediately after calling it because that will show immediately before the work is done.
I want that the application should get closed and it calls the library
method asynchronously.
If you want to submit the data before the application is closed then modify the event that handles when a form is about to close. Please understand this event only happens if the form is closed by the user. If you want to cover when the process is forced to exit you have to subscribe to that event and so something similar.
Furthermore there are ways to close a process and for none of these events to happen. Basically this solution only works if the process reports back to Windows that it is closing.
Of course you shouldn't submit data asynchronously if your program's process is about to end.
Related
We have a Winforms application which launches a WPF Dialog which I will refer to as the Wizard. The purpose of the Wizard is to open a number of text files and save their contents to a database. The time required to save these files to the DB varies from 15 to 60+ seconds. In order to give the Wizard UI responsiveness, the process of saving the text files to the database is done on a BackgroundWorker thread. Unfortunately, because of some legacy code in the Winforms host application, the Wizard is totally unresponsive for 80 - 90% of the time. For that reason, the Wizard is launched on its own worker thread.
//Put the Wizard on a separate thread to maintain UI
//responsiveness during the export process
Thread t = new Thread(LaunchBatchExportWizardView);
t.SetApartmentState(ApartmentState.STA);
t.Name = "WizardThread";
t.Start();
So in summary we have three principal threads, the Main thread which supports the Winforms host, the Wizard thread and the BackgroundWorker thread. A user may pause this export process by clicking on a button on the Wizard which sends a CancelAsync message to the BackgroundWorker thread. Inside the BackgroundWorker_DoWork event handler we check for this cancel message and, if found, discontinue processing and return. This triggers the BackgroundWorker_RunWorkerCompleted event handler where I can check the identity of the thread to which control has been returned by using Thread.CurrentThread.Name.
The first time that the user pauses the BackgroundWorker process, control is returned to the Wizard thread. If the user wants to resume the export process, we call RunWorkerAsync which in turn starts the BackgroundWorker_DoWork event handler. From observation I can see that this handler does not use the same thread which it previously used but instead uses a new one from the Thread Pool. For debugging purposes, I give this thread a name.
if(Thread.CurrentThread.Name == null)
{
Thread.CurrentThread.Name = "MyBackgroundWorkerThread"
+ "_" + _threadCounter.ToString();
_threadCounter++;
}
The first BackgroundWorker thread is named MyBackgroundWorkerThread_1, the second one MyBackgroundWorkerThread_2, etc.
Later when the user decides to pause the process again, control is not returned to the Wizard thread in the BackgroundWorker_RunWorkerCompleted event handler (as it was the first time) but instead to some new thread. However, this is not fatal and the user can still resume and the export process will pick up where it left off.
The problem arises, however, when we try to launch a custom warning dialog in the event that connectivity to the database is lost. Obviously the Wizard cannot perform its primary mission if it can't communicate with the database. If we launch this dialog after one or more Pause / Resume cycles, an exception is thrown with the message "The calling thread must be STA, because many UI elements require this". Because of this requirement, the Wizard thread is explicitly set to STA (see relevant code above) so if the database connectivity loss occurs before any Pause / Resume cycle, everything works just fine. This new thread, apparently is not STA and accordingly an exception is thrown.
One option which I tried was to test to see if at the point in time that we want to launch our DatabaseConnectivityLoss dialog we are on the Wizard thread. Since the Wizard thread is an explicitly named thread (see code above), I just test to see if the name property of the current thread is null:
if (Thread.CurrentThread.Name == null)
{
if (Application.Current == null)
{
new Application();
}
Thread t = new Thread(LaunchDatabaseConnectivityLossDialog);
t.SetApartmentState(ApartmentState.STA);
t.Name = "NewStaThread";
t.Start();
}
This works fine to launch the dialog without the previously mentioned exception but when we attempt to resume the export process after connectivity has been restored, the application hangs.
A second thing which I tried was to set a SynchronizationContext variable to hold a reference to the Wizard thread. It was my understanding that I could use this reference to launch my DatabaseConnectivityLoss dialog on the Wizard thread regardless of what thread was current at any time. To do this I set this variable in the constructor for the Wizard:
_synchronizationContext = SynchronizationContext.Current;
if (_synchronizationContext == null)
{//always true in my case because the wizard is a child of a Winforms app
_synchronizationContext = new SynchronizationContext();
}
However, when I later tried to use this SynchronizationContext to force my code back on to the Wizard thread, it fails:
`_synchronizationContext.Send(Test, null);
private void Test(object placeholder)
{
Debug.WriteLine(Thread.CurrentThread.Name);
}`
Thread.CurrentThread.Name usually returns null and in other cases returns "NewStaThread". I don't want to imply that this behavior is intermittent. It is just that I have tried many different variations and have called this method from many different locations under different circumstances.
It was my impression that synchronizationContext was supposed to hold a reference to the Wizard thread and when I call the Send method the callback method should execute on the Wizard thread.
Can anyone see which of my assumptions is invalid, or alternatively suggest an avenue for a solution.
Conceptually, I believe that either I have to force my application to return from the DoWork handler back to the Wizard thread or, alternatively, to force it back on to the Wizard thread before launching my DatabaseConnectivityLoss dialog. It is my understanding that I don't have access to the anonymous thread until it is too late to set it to STA which must be done prior to it starting.
The API doesn't officially support threading (see below) or a way to close an active document. That said, a work around to closing an active document is to call...
SendKeys.SendWait("^{F4}");
...from a separate thread. That works fine, except I need to loop through opening and closing several documents. If I put any code at all after thread, it will run it before closing the previous document. I have tried a number of standard threading callback methods including...
Task.Factory.StartNew(() =>
ThreadPool.QueueUserWorkItem(new WaitCallback
AutoResetEvent.WaitOne()
with no luck. And Thread.Sleep() just stalls the error/crash. Does anyone have any ideas.
"Revit's internals make use of multiprocessing in only a few select isolated locations. None of these locations currently encompass the code in the Revit API, or any part of it. Thus Autodesk does not recommend making any calls to the Revit API from within simultaneously executing parallel threads. It may be that some part of the Revit API is isolated enough to be able to execute successfully from within such threading code in a test environment; this should not be taken to be a guarantee that the same source code will function for any model or situation, or that a future change in Revit will not cause this code to cease to function."
public void OpenFile()
{
for (int i = 0; i < 3; i++)
{
uiApp.OpenAndActivateDocument(TargetPath(i));
ThreadPool.QueueUserWorkItem(CloseDocProc);
//any code here at all opens the next doc without closing the last
}
}
public void CloseDocProc(object stateInfo)
{
SendKeys.SendWait("^{F4}");
//can run code here
}
The problem was the threading, just like they said. Using any of the callback methods it would freeze right at that point. And you can only do a limited number of things in the thread, it would not let me open a document, no matter what!
The answer was to use a single-threaded timer.
System.Windows.Forms.Timer;
calling my Open() method every 10 seconds or so and stopping the timer and running the last bit of code when a counter reached a certain point.
Not sure if it could do the trick, but you can perhaps use this technique: http://adndevblog.typepad.com/autocad/2012/06/use-thread-for-background-processing.html
It's for AutoCAD, but I think it could work with Revit. Revit API, like the AutoCAD one, do not support multithreading. You should only call the API functions from the main thread.
You need if fact to marshal the call to the main thread. The simplest way to achieve that is creating a System.Windows.Forms.Control object on the main thread and call its Invoke() from the separate thread where you're closing the document.
Or you can also use the Idle Event in a creative way...
Create a state machine in your app idle event handler that interacts with your thread and which handles the revit calls.
Here's what I have. When my application starts up, it creates a thread and runs my startListening() function. But what it seems to do, is run any other functions called within startListening under the same thread. Is there a way I can make it so that ONLY the things immediately inside of startListening are ran with that thread, and not the functions called from within that?
It would just make it a lot easier for me when referencing controls and things that aren't within that thread so I don't have to Invoke each time.
EDIT: Maybe this isn't the right thing to be asking. I know I had to Invoke with setting textboxes, but now I need to make a timer enabled. Its not throwing any exceptions when I try to enable it, but rather just not "ticking". Here's my code:
private void beginListenerThread()
{
Thread thread1 = new Thread(startListening);
thread1.Start();
}
private void startListening()
{
timer1.enabled = true;
}
But it doesn't tick.
Thanks!
No, that's not possible automatically. If you are able to modify the method that should be called on another thread, change the calls to other methods so that they're run on the originating thread. If you're using Windows Forms, use this.Invoke or this.BeginInvoke, for example.
Yes, this is the kind of trouble you'll run into when you use a class that is not thread-safe on a thread. The Winforms Timer class generates Tick events from a little hidden helper window, a window that receives WM_TIMER messages generated by the Windows SetTimer() api function and turns them into Tick event calls. That window is created when you enable the timer.
What goes wrong here is that this window gets created on the wrong thread. It needs a message pump to dispatch the WM_TIMER notifications, that thread doesn't have one. It could have one by calling Application.Run() but you don't want to go there.
Follow the advice given in the MSDN Library article's Remarks section:
The Windows Forms Timer component is single-threaded, and is limited to an accuracy of 55 milliseconds. If you require a multithreaded timer with greater accuracy, use the Timer class in the System.Timers namespace.
Or the System.Threading.Timer class, a timer class that's a bit less cranky.
Assume that I have Silverlight app doing a call to a WCF service:
void DoStuff()
{
MyProxy proxy = new MyProxy();
proxy.DoStuffCompleted += DoStuffCompleted;
proxy.DoStuffAsync();
}
void DoStuffCompleted(object sender, DoStuffCompletedEventArgs e)
{
// Handle the result.
}
DoStuff is called by the UI thread. What thread will eventually call the DoStuffCompleted method? If I invoke two async calls at the same time, is there a possibility that both the completed events are fired simultaneously, on different threads?
The callback will be invoked on the main thread. Multiple responses will not occur simultaneously. The order of the response events could be unexpected. You may want to use the overload of proxy.DoStuffAsync that accepts "user state" object:
proxy.DoStuffAsync(object userState)
This will allow you to send something unique for each call so you can differentiate which response you're dealing with. Remember that if the WCF call returns an error you have no return value - so userState may be the only way to know which call failed (if it matters).
Update:
Found some more info (on SO) on how to make it use another thread:
Silverlight web service callback performance Follow the link there to Tomek's blog for lots more info.
The Completed event will occur on a different thread than the UI Thread. Multiple Completed events may be executed simultaneously on different threads because a thread pool is used to handle results.
Asynch calls are executed in the background thread pool. For each asynch call you shall have a separate thread from the pool.
DoStuffCompleted will be executed in the background pool thread.
Now, it is important to note that this
method is called on the background
worker thread. If we want to update
the UI with the newly obtained data
(say we want to update a data grid
control to display the customer data),
we have to be careful to do this on
the UI thread. If we don't, then all
manner of strange things may happen
and we will have a difficult time
diagnosing which bug to fix (from here)
I currently have a thread that listens for data from the network and then runs rules on it. I then want to pass the data to the GUI. I am worried about having a deadlock in the GUI. I cant figure out were to put the mutexes on the GUI side. I am also using c# and dotnet 3.5.
What I have come up with is
1) Using a timer to create an event and dump the thread. Worried about performance.
2) Use an intermediary event to copy the data to GUI.
3) Dig in and figure out thread safe way of using GUI.
What do you think is best way to proceed?
Edit: Here is the solution I am using. I pass in the changed element and then protect the big object with a mutex. I use helper function to switch threads using InvokeRequired then BeginInvoke with a delegate. Pulled from reading the answers and then following links until reaching Threading in Windows Forms by Jon Skeet.
delegate void UInt32ParameterDelegate(UInt32 n);
public void UpdateLocation(UInt32 n)
{
if (InvokeRequired)
{
// We're not in the UI thread, so we need to call BeginInvoke
BeginInvoke(new UInt32ParameterDelegate(UpdateLocation), new object[] { n });
return;
}
// Must be on the UI thread if we've got this far
this.engine.location.UpdateBusy.WaitOne();
// do the work in here
this.engine.location.UpdateBusy.ReleaseMutex();
}
Synchronization is very easy in Windows Forms. You can call Control.Invoke() in the background thread. The thread will stall until the delegate has finished running on the UI thread. No sync required at all.
If stalling the thread is a problem, use Control.BeginInvoke(). You'll have to protect the object(s) you pass to the delegate with a lock if the thread might alter them while it continues running. That's rarely the case in a producer-consumer scenario, the thread can simply create new objects.
Do make sure that you don't Invoke() too often. Do it more frequently than about 1000 times per second and the UI thread will stop pumping Windows messages, being bogged down by handling the invoke requests. Since it is human eyes you're trying to please, invoking more than about 25 times per second is just wasted effort. Pool intermediate results in a collection object.
I hope I understand your problem correctly.
After the background thread reads the data and does whatever it wants, it should use Invoke to call a method on the GUI thread. That method would update anything that should be updated in the GUI.
Never read from the network on the GUI thread. It's only a matter of time before your application runs during a network outage and your GUI hangs as a result. This will really frustrate your users.
In your situation I think the best approach is to have a background thread complete the read operation. Then take the resulting data and move it back to the GUI thread via a SynchronizationContext Post or Send method.
you should just pass an event from your network thread to your UI thread.
then cross threads using begininvoke so you don't get a cross thread exception.
Need help getting info across a UI thread and another thread in C#
You could use a backgroundworker that will process the datareading in a background thread and when it's done you can end the backgroundworker triggering it's RunWorkerCompletedEventHandler. In the RunWorkerCompletedEventHandler you can update your GUI thread with the result.
Isn't easier to just throw a delegate who raise an event that inform the form to refresh itself?