C# Delay Modal Dialog showing on Load, whilst allowing execution to continue - c#

I have a form being displayed by a static method.
This static method calls ShowDialog on the form:
//Static method on LockWaitForm
public static LockDetails Lock(string lockedMessage, object[] params parameters)
{
using (LockWaitForm form = new LockWaitForm(parameters))
{
form._lockedMessage.Text = lockedMessage;
DialogResult result = form.ShowDialog();
return new LockDetails (form._lockStatus, form._lock);
}
}
What I want is the OnLoad method of the dialog to wait up to one second before it shows, so it will only display if a lock on a record cannot be achieved after 1 second. It will happily drop out before one second if a lock is obtained before 1 second, setting its DialogResult to OK.
All functionality works fine except the hiding of the Dialog box for 1 second. All 'Visible = false' calls are ignored, and I can kind of understand why they would do that. The problem with this is that a false 'record is locked' will flash up for a sub second every time the form is used and a lock can be obtained without an issue.
I can figure out a few hacky ways to delay the visibility of the dialog box
Set Opacity to 0% - this does not work for Remote Desktop Connections
Have the form only be initialized by the static method once the 1 second has elapsed. This is promising, but requires a lot of repeated static vs non static code to handle the setup and disposal of the lock, and still feels a bit hacky.
Is it possible to limit the display of a Modal Dialog called through ShowDialog? I am reluctantly happy to PInvoke at this point (though I do want to limit non-64bit code for future requirements)
EDIT
By moving my acquire lock code to the form's constructor instead of Load, I can keep the locking code in one place, and just wait while the form's lock status is in a Waiting state before calling ShowDialog. Still feels dirty, but the cleanest method so far

I would refactor the application to not even display the modal dialog until the lock process has failed to achieve a lock for one second.

Not sure this would work, but: in your LockWaitForm, override ShowDialog() with your own version that calls the code to acquire a lock (or whatever it's doing), and then if more than 1 second passes, call this.ShowDialog() (the real one). This should allow you to only change the code in LockWaitForm, and not anywhere else.
Sorry, my laptop with Visual Studio is in a friend's trunk right now, so I can't check if this is possible.

What sort of lock? Just a normal thread lock? Can you just use Monitor.TryEnter?
If it returns false, the lock is busy and you can pop some sort of retry/cancel lock-waiting window.
If it's true though, just proceed with life as normal.
As a general comment, I really agree with Eric J that you should not be displaying the form until the lock has failed. It seems awkward to be using the error dialog to perform the ordinary workflow, and trying to secretly hide it in the non-error case.
Instead, you should have a proper workflow doing the lock entirely outside the error dialog, and pop the dialog only on the error workflow.

Related

BackgroundWorker problems on exit

I am having a bit of a conundrum here, and would like to know a couple of things:
Am i doing this wrong?
What is the expected behaviour of a backgroundworker in different scenarios...
If possible, get an answer as to why i am getting specific behaviour would be nice...
For point 1, and ultimately 3 as well, i will explain what i am doing in Pseudo-Code so that you have the details without actually spitting out thousands of lines of code. While i write this post, i will look at the code itself to ensure that the information is accurate as far as when and what is happening. At the very end, i will also detail what is happening and why i am having issues.
Pseudo-Code details:
I have a main UI thread (WinForms form), where after selecting a few configuration options you click a button.
This button's event does some preliminary setup work in memory and on the file system to get things going and once that's done fires off ONE backgroundworker. This backgroundworker initializes 5 other backgroundworkers (form scope variables), sets their "Done" flags (bool - same scope) to true, sets their "Log" vars to a new List<LogEntry> (same scope) and once that's done calls a method called CheckEndConditions. This method call is done within the DoWork() of the initial backgroundworker, and not in the RunWorkerCompleted event.
The CheckEndConditions method does the following logic:
IF ALL "Done" vars are set to True...
Grab the "Log" vars for all 5 BWs and adds their content to a master log.
Reset the "Log" vars for all 5 BWs to a new List<LogEntry>
Reset the "Done" vars for all 5 BWs to False.
Call MoveToNextStep() method which returns an Enum value representative of the next step to perform
Based on the result of (5), grab a List<ActionFileAction> that needs to be processed
Check to ensure (6) has actions to perform
If NO, set ALL "Done" flags to true, and call itself to move to the next step...
If YES, partition this list of actions into 5 lists and place them in an array of List<ActionFileAction> called ThreadActionSets[]
Check EACH partitioned list for content, and if none, sets the "Done" flag for the respective thread to true (this ensures there are no "end race scenarios")
Fire off all 5 threads using RunWorkerAsync() (unless we are at the Finished step of course)
Return
Each BW has the exact same DoWork() code, which basically boils down to the following:
Do i have any actions to perform?
If NO, set my e.Result var to an empty list of log entries and exit.
If YES, loop for each action in the set and perform 4-5-6 below...
What context of action am i doing? (Groups, Modules, etc)
Based on (4), what type of action am i doing? (Add, Delete, Modify)
Based on (5), perform the right action and log everything you do locally
When all actions are done, set my e.Result var to the "log of everything i've done", and exit.
Each BW has the same RunWorkerCompleted() code, which basically boils down to the following:
TRY
From the e.Result var, grab the List<LogEntry> and put it in my respective thread's "Log" var.
Set my respective "Done" var to true
Call CheckEndConditions()
CATCH
Set my respective "Done" var to true
Call CheckEndConditions()
So that is basically it... in summary, i am splitting a huge amount of actions into 5 partitions, and sending those off to 5 threads to perform them at a faster rate than on a single thread.
The Problem
The problem i am having is that i often find myself, regardless of how much thought i put into this for race scenarios (specifically end ones), with a jammed/non-responsive program.
In the beginning, i had setup my code inefficiently and the problem was with End Race Scenarios and the threads would complete so fast that the last call made to CheckEndConditions saw one of the "Done" vars still set to false, when in fact it wasn't/it had completed... So i changed my code to what you see above which, i thought, would fix the problem, but it hasn't. The whole process still jams/falls asleep, and no threads are actually running any processing when this happens which means that something went wrong (i think, not sure) with the last call to CheckEndConditions.
So my 1st question: Am i doing this wrong? What is the standard way of doing what it is i want to do? The logic of what i've done feels sound to me, but it doesn't behave how i expect it to so maybe the logic isn't sound? ...
2nd question: What is the expected behaviour of a BW, when this scenario occurs:
An error occurred within the DoWork() method that was un-caught... does it fire off the RunWorkerCompleted() event? If not, what happens?
3rd question: Does anyone see something obvious as to why my problem is occurring?
Thanks for the help!
Reposting my comment as answer per OP's request:
The RunWorkerCompleted event will not necessarily be raised on the same thread that it was created on (unless it is created on UI thread) See BackgroundWorker RunWorkerCompleted Event
See OP comments for more details.

Need second (and third) opinions on my fix for this Winforms race condition

There are a hundred examples in blogs, etc. on how to implement a background worker that logs or gives status to a foreground GUI element. Most of them include an approach to handle the race condition that exists between spawning the worker thread, and creating the foreground dialog with ShowDialog(). However, it occured to me that a simple approach is to force the creation of the handle in the form constructor, so that the thread won't be able to trigger an Invoke/BeginInvoke call on the form prior to its handle creation.
Consider a simple example of a Logger class that uses a background worker thread to log to the foreground.
Assume, also, that we don't want NLog or some other heavy framework to do something so simple and lightweight.
My logger window is opened with ShowDialog() by the foreground thread, but only after the background "worker" thread is started. The worker thread calls logger.Log() which itself uses logForm.BeginInvoke() to update the log control correctly on the foreground thread.
public override void Log(string s)
{
form.BeginInvoke(logDelegate, s);
}
Where logDelegate is just a simple wrapper around "form.Log()" or some other code that may update a progress bar.
The problem lies in the race condition that exists; when the background worker thread starts logging before the foreground ShowDialog() is called the form's Handle hasn't yet been created so the BeginInvoke() call fails.
I'm familiar with the various approaches, including using a Form OnLoad event and a timer to create the worker task suspended until the OnLoad event generates a timer message that starts the task once the form is shown, or, as mentioned, using a queue for the messages. However, I think that simply forcing the dialog's handle to create early (in the constructor) ensures there is no race condition, assuming the thread is spawned off by the same thread that creates the dialog.
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.handle(v=vs.71).aspx
MSDN says: "If the handle has not yet been created, referencing this property will force the handle to be created."
So my logger wraps a form, and its constructor does:
public SimpleProgressDialog() {
var h = form.Handle; // dereference the handle
}
The solution seems too simple to be correct. I'm specifically interested in why the seemingly too simple solution is or isn't safe to use.
Any comments? Am I missing something else?
EDIT: I'm NOT asking for alternatives. Not asking how to use NLog or Log4net, etc. if I were, I'd write a page about all of the customer constraints on this app, etc.
By the number of upvotes, there are a lot of other people that would like to know the answer too.
If you are concerned that referencing Control.Handle relies on a side effect in order to create the handle, you can simply call Control.CreateControl() to create it. However, referencing the property has the benefit of not initializing it if it already exists.
As for whether this is safe or not assuming the handle is created, you are correct: as long as you create the handle before spawning the background task on the same thread, you will avoid a race condition.
My two cents: there's no real need to force early handle creation if the logging framework simply maintains a buffer of undisplayed log entries while the handle has not been created. It could be implemented as a Queue, or many other things. Messing with the order of handle creation in .NET makes me squeamish.
I think the only danger is decreased performance. Handle creation is deferred in winforms to speed things up. However, since it sound like this is a one-time operation, it doesn't sound costly, so I think your approach is fine.
You can always check the IsHandleCreated property of your form to see if the handle has been built yet; however, there are some caveats. I've been in a similar spot to yours, where winforms controls are being created/destroyed dynamically with lots of multithreading going on. The pattern we wound up using was quite a bit like this:
private void SomeEventHandler(object sender, EventArgs e) // called from a bg thread
{
MethodInvoker ivk = delegate
{
if(this.IsDisposed)
return; // bail out! Run away!
// maybe look for queued stuff if it exists?
// the code to run on the UI thread
};
if(this.IsDisposed)
return; // run away! killer rabbits with pointy teeth!
if(!this.IsHandleCreated) // handle not built yet, do something in the meantime
DoSomethingToQueueTheCall(ivk);
else
this.BeginInvoke(ivk);
}
The big lesson here is to expect a kaboom if you attempt to interact with your form after it has been disposed. Don't rely on InvokeRequired, since it will return false on any thread if the control's handle hasn't been created yet. Also don't rely solely on IsHandleCreated since that will return false after the control has been disposed.
Basically, you have three flags whose state will tell you what you need to know about the control's initialization state and whether or not you're on a BG thread relative to the control.
The control can be in one of three initialization states:
Uninitialized, no handle created yet
InvokeRequired returns false on every thread
IsHandleCreated returns false
IsDisposed returns false
Initialized, ready, active
InvokeRequired does what the docs say
IsHandleCreated returns true
IsDisposed returns false
Disposed
InvokeRequired returns false on every thread
IsHandleCreated returns false
IsDisposed returns true
Hope this helps.
Since you do create the window on the calling thread you can end up with deadlocks. If the thread that creates the window has no message pump running your BeginInvoke will add your delegate call to the message queue which will never be emptied, if you do not have an Application.Run() on the same thread which will process the window messages.
It is also very slow to send around window messages for each log message. It is much better to have a producer consumer model where your logging thread adds a message to a Queue<string> which is emptied by another thread. The only time you need to lock is when you enqueue or dequeue a message. The consumer thread can wait for an event with a timeout to start processing the next message when either the event was signaled or the timeout (e.g. 100ms) has elapsed.
A thread safe blocking Queue can be found here.

how to implement a step-by-step button in c#?

I implemented an algorithm in c# and I want to make a gui for it, in my gui i want to put a button that with any click the gui shows a step forward in algorithm, so i think i need to put something like pause? statements in my code that with any click it can resume. how should i do that? or is there any other suggestion for implementing this idea?
It sounds like really you need to turn your algorithm into a state machine - instead of actively "pausing" it, you would actively "advance" it.
You may find iterator blocks useful... if your algorithm is pretty much in one method at the moment, you may be able to change it to insert a yield return statement at the end of each logical step, returning some indication of the current status.
That's not an entirely normal use of iterator blocks, but it could be the simplest way forward here. Your UI would call GetEnumerator once at the start, and then MoveNext() each time the button is clicked (followed by accessing the Current property to get at the current state). Don't forget to dispose of the iterator when you've finished with it.
Run your algorithm in a thread different than your UI thread.
For synchronization, create some kind of wait handle, e.g. an AutoResetEvent.
The "pause" statement you are looking for is myWaitHandle.WaitOne() (called by your algorithm thread).
Allow the algorithm to continue by executing myWaitHandle.Set() in your UI thread.
This method has the advantage that your user interface stays responsive while a step of your algorithm is being executed.
You have to decide what is a "step" in your algorithm. Then you need to rewrite your algorithm and wrap it in a class with the following interface:
interface ISteppedAlgorithm
{
bool NextStep(); //returns if the algorithm is finished
IStepResult LastStepResult {get;}
}
and now your GUI will drive the algorithm prepared in this way. After you press the button, the NextStep() method will be invoked. If it returns false disable the button (or indicate in whatever other way that its all done). Then read the LastStepResults and update the display.h
From your description I think you want a "wizard" that is basically an application with previous / next buttons.
http://www.differentpla.net/content/2005/02/implementing-wizard-c
However If you just have a long running task and want to have some breaks in it, there are different ways to solve it.
Sperate you task in multiple methods.
After a method is completed, wait until the user hit's next.
Let the task run in it's own thread and at a point where it should wait let the thread sleep until you set a specific var:
LongRunningMethod1();
while(continue1 == true)
{
Thread.Sleep(50);
}
LongRunningMethod2()
while(continue2 == true)
{
Thread.Sleep(50);
}
Set continue1 and 2 to true in your main thread to let the background thread do his work.
If it's just to "observe" the state of the algorithm as it develops, why not add some events (probably just one at the end) and let the event handler store an array of the states. The UI can simply iterate forward\backwards over this as and when needed.

How can a function be triggered with an event?

I have an application wherein I would like a function to be executed in the same thread when an event is fired. For example:
SomeCode()
{
// Do something...
// Fire event to run SomeOtherCode().
}
SomeOtherCode()
{
// Do something else...
}
I do not want to simply call the function because it will hold things up. SomeOtherFuction() needs to be executed in the same thread because it needs to access the form controls, and I need it to begin execution from an event trigger firing. I am using Microsoft Visual C# 2008 Express Edition. Thanks.
::: EDIT:::
Additional Details: The bottom line is that the contrustor of my form application is taking far too long to complete, and it is causing a significant delay, from when the user launches the application to when the application window appears on the display. This is not a problem on faster computers, but on slower computers it is a big problem. I need to exit the contrustor as soon as possible, thus allowing the framework to draw the application window, and continue initialization outside the constructor. (All essential items would still be initialized inside the constructor.)
An event-triggered function call would be ideal. I would prefer not to use a timer. Interlacing the affected code with Invokes is impractical in my situation and would require much more time to implement than I have to work on this. A simple example of an event-driven function call is all I'm really looking for. Thanks.
From your posts it's seems like you're confusing a few issues. The standard pattern in .Net is for events to run synchronously. The following lines are essentially identical in terms of when they execute.
Option #1
SomeCode();
SomeOtherCode();
Option #2
SomeEvent += delegate { SomeOtherCode(); }
...
SomeCode();
SomeEvent(this,EventArgs.Empty);
If you want to unblock the UI thread and run the code later you'll need to use some mechanism to delay the running of the SomeOtherCode function. The easiest way to do this in a WinForms application is to use a WinForms Timer instance. This will raise an event on the UI thread at a later point in time that you can respond to. It also won't block the UI thread during this time allowing your form to continue processing.
You seem to be asking to run SomeOtherCode() later.
You can call BeginInvoke (either from the UI thread or from any other thread) to queue a function to run during the next message loop:
BeginInvoke(new Action(SomeOtherCode));
It seems that you would want to add an event to the class that exposes the SomeCode method. Then, the class that implements the SomeOtherCode method would attach an event handler that calls the SomeOtherCode method.
It's completely viable to have this done in one class, in case you have some sort of state model where you want to add/remove the call depending on some other logic.
I think you want to put SomeOtherCode into a Task or BackgroundWorker, which would then synchronize with the UI thread to send it updates.
I recently posted on my blog a class that makes updating the UI from a Task as easy as from a BGW. I do recommend using Task rather than BackgroundWorker.
Simialr to what Stephen said, I would recommend that you move as much of that initialization code to a background thread or task. Let the background thread do as much work as possible, then send the necessary window updates to your UI thread via Action<>'s. Here's some quick psuedo-sample code:
protected void LoadMyListInBackground(object state)
{
List<string> myList = Databse.FetchMyList(myParameters); // This take a while, so the UI thread isn't waiting
ShowMyList(myList);
}
protected void ShowMyList(List<string> theList)
{
if(InvokeRequired)
Invoke(new Action<List<string>>(ShowMyList, theList);
else
{
foreach(string item in theList)
myListBox.Items.Add(item);
}
}
In this example the UI thread is free to keep drawing your window while the background thread does the lengthy database work. The problem is, even if you fire an event outside of your constructor, and that event occurs on the UI thread and takes a long time, the user might see the window but that window is going to 'freeze' and possibly appear to be 'crashed' to the user. This technique prevents that and provides a better user experience.

"Emulating" Application.Run using Application.DoEvents

I'm getting in trouble. I'm trying to emulate the call Application.Run using Application.DoEvents... this sounds bad, and then I accept also alternative solutions to my question...
I have to handle a message pump like Application.Run does, but I need to execute code before and after the message handling. Here is the main significant snippet of code.
// Create barrier (multiple kernels synchronization)
sKernelBarrier = new KernelBarrier(sKernels.Count);
foreach (RenderKernel k in sKernels) {
// Create rendering contexts (one for each kernel)
k.CreateRenderContext();
// Start render kernel kernels
k.mThread = new Thread(RenderKernelMain);
k.mThread.Start(k);
}
while (sKernelBarrier.KernelCount > 0) {
// Wait untill all kernel loops has finished
sKernelBarrier.WaitKernelBarrier();
// Do application events
Application.DoEvents();
// Execute shared context services
foreach (RenderKernelContextService s in sContextServices)
s.Execute(sSharedContext);
// Next kernel render loop
sKernelBarrier.ReleaseKernelBarrier();
}
This snippet of code is execute by the Main routine. Pratically I have a list of Kernel classes, which runs in separate threads, these threads handle a Form for rendering in OpenGL. I need to synchronize all the Kernel threads using a barrier, and this work perfectly.
Of course, I need to handle Form messages in the main thread (Main routine), for every Form created, and indeed I call Application.DoEvents() to do the job.
Now I have to modify the snippet above to have a common Form (simple dialog box) without consuming the 100% of CPU calling Application.DoEvents(), as Application.Run does.
The goal should be to have the snippet above handle messages when arrives, and issue a rendering (releasing the barrier) only when necessary, without trying to get the maximum FPS; there should be the possibility to switch to a strict loop to render as much as possible.
How could it be possible?
Note: the snippet above must be executed in the Main routine, since the OpenGL context is created on the main thread. Moving the snippet in a separated thread and calling Application.Run is quite unstable and buggy...
There isn't anything fundamentally wrong with calling Application.DoEvents() in a loop. That's what Form.ShowDialog() does. It takes counter-measures to ensure the user cannot get into trouble: it disables all windows other than the dialog so the user cannot exit the application or start the dialog again.
You'll need to create your own, set a global flag that indicates that your main window was closed so you can immediately exit the loop without calling any more code when the rug is pulled out from under you.
You'll need to yield the processor to avoid 100% CPU load. The easiest way to do that is by calling Thread.Sleep(1). Check my answer in this thread for an example.
Don't do it - this stuff is pretty complex and I'm pretty sure you get nothing but trouble for implementing it yourself.
Can't you use Application.AddMessageFilter() to implement what you need?
If you're going to build a message loop like this, you should PInvoke the actual Win32 message handling functions (which is all that Application.Run is doing behind the scenes -- it has an internal class called UnSafeNativeMethods that maps a bunch of them).
If you don't need to keep processing between message calls -- in other words, if it's safe for your thread to sleep when it's not actively handling a message -- then bind WaitMessage from User32.dll and put it in a loop like:
while (WaitMessage())
{
Application.DoEvents();
}
If you need more help let me know. I'm in the middle of a VS reinstall right now or I'd post a sample application showing how to do the binding and PInvoke.

Categories

Resources