Is Application.DoEvents() a form of Multitasking? - c#

I am pretty sure Applicataion.DoEvents() in Windows Forms. is a very early, very primitive, WindowsForms only form of Multitasking. It has all the telltales and mechanics:
Pausing execution of the calling Event.
Making the rest of said Event a continuation to be run later.
Allowing the other Events/Processes to run. Just with some extra issues, because the MT is implemented via the EventQueue. Possibly even a recursive call to the Queue.
But I just ran into a person that insists it has "nothing to do with Multitasking", which I cannot reconcile with my understanding of the Function or the of Multitasking.
Note: I explicitly consider Mutltithreading only an implementation for Multitasking. It is clear that DoEvents() is not a form of Multithreading, as we all know how poorly that one works in GUI Environments.

I am pretty sure it is a very early, very primitive, Windows Forms only form of Multitasking
You are pretty close to correct on all counts except for your conjecture that it is for WinForms only. "DoEvents" precedes WinForms; it was present in Visual Basic long before WinForms was invented, and "pump the message queue" obviously precedes VB also. And it was a bad idea and easily abused then too.
Making the rest of said Event a continuation to be run later.
DoEvents doesn't really make anything into a continuation the way that say, await does. Whatever event is currently "in flight" when DoEvents is called has its state on the stack, and the stack is the implementation of continuation in this case. This is another point against DoEvents -- unlike await, it eats stack, and therefore can contribute to an overflow.
I just ran into a poster that insists it has "nothing to do with Multitasking".
You should ask the author for clarification then, since that certainly sounds wrong.

Well, it's called Preemptive Multitasking, meaning "interrupting a task". You do multiple Tasks, but never two at the same time. It's not about using multiple cores of the CPU, but a way to control multiple activities inside your program.
Common Sample is, to give the program a chance to handle mouse movement by the user, while doing a lengthy operation, running something that can be considered a "batch"-job.
Normally you don't have to care about this "DoEvents", but if you know, you have a procedure running for more than 1 second, you should call it manually, you pass the control to another method thereby, you stop your own code, let other code run, and than you continue with your own code.
So it's never asynchronous, but still some kind of "multitasking".
It's more a control structure, the important thing is, you do not know what's going on inside, you call it "just for case" - somebody else might need the CPU for a millisecond.
There is no external task scheduler interrupting your code and doing a context switch, you have to "behave" by interrupting your code yourself, if you do something lengthy. It is a convention that you do only "small" things in event handlers and return the control to Windows as soon as possible,either by finishing the method, or by calling DoEvents.

Related

What would be a use case for Thread.Sleep(Timeout.Infinite)?

I happened to lay my eyes on an intellisense tool tip regarding the parameter passed to System.Threading.Thread.Sleep(int millisecondsTimeout), saying something like "(…) Specify System.Threading.Timeout.Infinite to block the thread indefinitely". And I am intrigued.
I can understand why one might include short inactive delays within a possibly endless loop, thus yielding processing power to other executing threads when no immediate action in the sleeping thread is required, although I typically prefer implementing such delays with EventWaitHandlers so that I can avoid waiting a full sleeping delay if I signal the thread to gracefully end its execution from a different thread.
But I cannot see when I might need to suspend a thread indefinitely, and in a way that, as far as I can tell, can only be interrupted through a rather ungraceful Thread.Abort()/ThreadAbortException pair.
So what would be a working scenario where I might want to suspend a thread indefinitely?
It is a pretty long story and I have to wave my hands a bit to make it understandable. Most programmers think that Thread.Sleep() puts the thread to sleep and prevents it from executing any code. This is not accurate. Thread.Sleep(Infinite) is equivalent to Application.Run(). No kidding.
This doesn't happen very often in real life, it is mostly relevant in custom hosting scenarios. Getting code to run on a specific thread is in general an important feature to deal with code that is not thread-safe and the major reason why Application.Run() exists. But Windows exposes another way to do at a much lower level, the underlying api for this is QueueUserAPC(). The .NET analogue of this function is BeginInvoke().
This requires the thread to co-operate, just like it does when it calls Application.Run(). The thread must be in an "alertable wait state", executing a blocking function that can be interrupted. The CLR does not execute the sleep by itself, it passes the job to the CLR host. Most hosts will simply execute SleepEx(), passing TRUE for the bAlertable argument. The thread is now in a state to execute any requests posted by QueueUserAPC(). Just like it will be when it is actively executing inside the Application.Run() dispatcher loop.
The kernel feature is not otherwise exposed at all in the framework. It is the kind of code that is very hard to get right, re-entrancy bugs are pretty nasty. As most programmers that were bitten by Application.DoEvents() or a poorly placed MessageBox.Show() can attest. It is however a valid scenario in a custom hosting scenario. Where the host can get C# code to run on a specific thread, using this mechanism. So it is possible to pass Infinite because the designers did not want to intentionally disable this scenario. If this is made possible at all by the host author then they'd let you know about it. I don't know of a practical example.
More practically, you do use this feature every day. It is the way that System.Threading.Timer and System.Timers.Timer are implemented. Done by a thread inside the CLR which is started as soon as you use any timer, it uses SleepEx(INFINITE, TRUE) at its core.
You can use .Interrupt() to wake a sleeping thread (causing ThreadInterruptedException in the code that was calling .Sleep(), which can be caught and handled), so this provides a mechanism to say "sleep until someone prods you". I'm not saying it is necessarily the best mechanism for this, but: it may have uses for you.

How InvokeRequired and Invoke let us make app thread safe

How InvokeRequired and Invoke let us make our apps thread safe.
Let's consider such code:
private void ThreadSafeUpdate(string message)
{
if (this.textBoxSome.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(msg);
this.Invoke
(d, new object[] { message });
}
else
{
// It's on the same thread, no need for Invoke
this.textBoxSome.Text = message;
}
}
Is it possible to change state of InvokeRequired after InvokeRequired and before Invoke? If not, then why?
How does Invoking make it thread safe?
If InvokeRequired illustrate is current thread owning control, how would the thread know that it is or it is not the owner.
Let's consider that SomeMethod() is currently running on Thread1. We would like to call it from Thread2. Internally this method updates some field. Does Method.Invoke contain some kind of lock mechanism internally?
What if SomeMethod() takes very long time and we would like to run something other on the control owner thread. Does Invoking lock the owner thread or is it some kind of a background thread safe task?
ThreadSafeUpdate() //takes 5 minutes in Thread2
ThreadSafeUpdate() //after 2 minutes, we are running it in other thread2
ThreadSafeUpdate() //next run from Thread3
I think it is some kind of general pattern which can be implemented outside of winforms, what's its name?
Is it possible to change state of InvokeRequired
Yes, and it is a pretty common occurrence. Either because you started the thread too soon, before the form's Load event fired. Or because the user closed the window just as this code is running. In both cases this code fails with an exception. InvokeRequired fails when the thread races ahead of the window creation, the invoked code fails when the UI thread races ahead of the thread. The odds for an exception are low, too low to ever diagnose the bug when you test the code.
How Invoking make it thread safe?
You cannot make it safe with this code, it is a fundamental race. It must be made safe by interlocking the closing of the window with the thread execution. You must make sure that the thread stopped before allowing the window to close. The subject of this answer.
how would he know that he is or he is not owner.
This is something that can be discovered with a winapi call, GetWindowsThreadProcessId(). The Handle property is the fundamental oracle for that. Pretty decent test, but with the obvious flaw that it cannot work when the Handle is no longer valid. Using an oracle in general is unwise, you should always know when code runs on a worker thread. Such code is very fundamentally different from code that runs on the UI thread. It is slow code.
We would like to call it from Thread2
This is not in general possible. Marshaling a call from one thread to a specific other thread requires that other thread to co-operate. It must solve the producer-consumer problem. Take a look at the link, the fundamental solution to that problem is a dispatcher loop. You probably recognize it, that's how the UI thread of a program operates. Which must solve this problem, it gets notifications from arbitrary other threads and UI is never thread-safe. But worker threads in general don't try to solve this problem themselves, unless you write it explicitly, you need a thread-safe Queue and a loop that empties it.
What's if SomeMethod() takes very long time
Not sure I follow, the point of using threads is to let code that takes a long time not do anything to harm the responsiveness of the user interface.
I think it is some kind of general pattern
There is, it doesn't look like this. This kind of code tends to be written when you have an oh-shoot moment and discover that your UI is freezing. Bolting threading on top of code that was never designed to support threading is forever a bad idea. You'll overlook too many nasty little details. Very important to minimize the number of times the worker thread interacts with the UI thread, your code is doing the opposite. Fall in the pit of success with the BackgroundWorker class, its RunWorkerCompleted event gives a good synchronized way to update UI with the result of the background operation. And if you like Tasks then the TaskScheduler.FromCurrentSynchronizationContext() method helps you localize the interactions.
Usually, no. But it could happen if you're using await between the InvokeRequired check and Invoke call without capturing the execution context. Of course, if you're already using await, you're probably not going to be using Invoke and InvokeRequired.
EDIT: I just noticed that InvokeRequired will return false when the control handle hasn't been created yet. It shouldn't make much of a difference, because your call will fail anyway when the control hasn't quite been created yet, but it is something to keep in mind.
It doesn't make it thread-safe. It just adds the request to the control's queue, so that it's executed the next available time on the same thread the control was created on. This has more to do with windows architecture than with general thread-safety. The end result, however, is that the code runs on a single thread - of course, this still means you need to handle shared state synchronization manually, if any.
Well, it's complicated. But in the end, it boils down to comparing the thread ID of the thread that created the control, and the current thread ID. Internally, this calls the native method GetWindowThreadProcessId - the operating system keeps track of the controls (and more importantly, their message loops).
Invoke cannot return until the GUI thread returns to its message loop. Invoke itself only posts the command to the queue and waits for it to be processed. But the command is run on the GUI thread, not the Invoke-caller. So the SomeMethod calls in your example will be serialized, and the Invoke call itself will wait until the second call finishes.
This should already be answered. The key point is "only run GUI code on the GUI thread". That's how you get reliable and responsive GUI at all times.
You can use it anywhere you've got a loop or a wait on some queue. It probably isn't all that useful, although I have actually used it already a few times (mostly in legacy code).
However, all of this is just a simple explanation of the workings. The truth is, you shouldn't really need InvokeRequired... well, ever. It's an artifact of a different age. This is really mostly about juggling threads with little order, which isn't exactly a good practice. The uses I've seen are either lazy coding, or hotfixes for legacy code - using this in new code is silly. The argument for using InvokeRequired is usually like "it allows us to handle this business logic safely whether it runs in the GUI thread or not". Hopefully, you can see the problem with that logic :)
Also, it's not free thread-safety. It does introduce delays (especially when the GUI thread is also doing some work that isn't GUI - very likely in code that uses InvokeRequired in the first place). It does not protect you from accesses to the shared state from other threads. It can introduce deadlocks. And don't even get me started on doing anything with code that uses Application.DoEvents.
And of course, it's even less useful once you take await into consideration - writing asynchronous code is vastly easier, and it allows you to make sure the GUI code always runs in the GUI context, and the rest can run wherever you want (if it uses a thread at all).

System.Threading Sleep function help? (C#)

I'm new in C# and I'm using System.Threading.
I have this code:
UISystem.SetScene(Scene_Menu);
Thread.Sleep (9000);
p.Text="HELLO";
Thread.Sleep(9000);
p.Text="WORLD";
It delays 18 seconds, but the p.Text="HELLO" doesn't show between the sleep functions. What's the problem with my code?
Thanks.
Timers don't work since I can't edit p from a separate thread.
Application.DoEvents() is a Windows Forms function, I'm building an application in PS Vita.
You have discovered why you should never use Thread.Sleep. It is useful for only two things. (1) Writing test cases that need to simulate a thread being busy for a certain number of seconds, and (2) Sleeping for zero milliseconds tells the operating system "I cede the rest of my time slice to another process if there exists one that wants it"; it's a politeness thing.
You should never use thread.Sleep to introduce a delay as you are doing for exactly the reason you have discovered. You are setting a property, but setting a property does not cause the operating system to repaint the screen. Consider if it did; you might have a thousand property sets in a method, and you would have to repaint the screen after all of them, which would look ugly and be very slow.
Instead what happens is the property is set and the object makes a note to the operating system that says when this thread is available to handle operating system messages again, please repaint me. Your program is, instead of telling the operating system "I'm done, go ahead and see if there are any message for me" that instead you want the thread to do nothing for nine seconds.
Now, you can tell the program to check for messages by calling DoEvents but using DoEvents is also a bad idea and you should not do it. Doing so essentially causes your program to exhibit symptoms of Attention Deficit Disorder; you have not finished the current job and you are looking to see if there are new jobs to do without removing the old jobs from the call stack! Suppose those new jobs in turn get interrupted, and so on, and so on. The stack grows without bound, which is very bad. DoEvents is a "worst practice", just like sleeping a thread. You can get away with it in small simple programs but it leads to big trouble when the program becomes complex.
Moreover: yes, DoEvents will paint your control, but that is all it will do. For the next nine seconds, the application will appear to the user to be completely hung. That is a very bad user experience.
The right thing to do if you want to introduce a delay is to asynchronously wait. In C# 4 and earlier the standard way to do that is to create a timer, and when the timer ticks, do the next thing.
Now, you say that you cannot use a timer because you need to access the control from the UI thread. That's fine. The timer's tick event handler will run on the UI thread, not on a separate thread. You can safely use a timer.
In C# 5, the right thing to do is to use the new await keyword to introduce an asynchronous wait. That is, a wait that does other stuff while it is waiting, instead of going to sleep while it is waiting. In C# 5 you would write your code as:
UISystem.SetScene(Scene_Menu);
await Task.Delay (9000);
p.Text="HELLO";
await Task.Delay(9000);
p.Text="WORLD";
C# 5 is at present in beta; for details on this new feature see:
http://msdn.microsoft.com/en-us/async
For a gentle introduction to async and an explanation of why DoEvents is bad news, see my MSDN magazine article:
http://msdn.microsoft.com/en-us/magazine/hh456401.aspx

Alternative to Thread.Sleep that keeps the UI responsive?

I'm doing all this in C#, in Visual Studio 2008.
I want to slow down the work of my algorithm so that the user can watch it's work. There is a periodic change visible at the GUI so I added Thread.Sleep after every instance.
Problem is that Thread.Sleep, when set to at least a second, after a few instances of Thread.Sleep (after few loops) simply freezes entire GUI and keeps it that way till program completion. Not right away, but it always happens. How soon depends on the length of the sleep.
I have proof that entire program does not freeze, it's working it's thing, even the sleep is making pauses of correct length. But the GUI freezes at certain point until the algorithm ends, at which point it shows the correct final state.
How to solve this issue? Alternative to pausing algorithm at certain point?
First off, don't make the user wait for work that is done before they even think about when it will be finished. Its pointless. Please, just say no.
Second, you're "sleeping" the UI thread. That's why the UI thread is "locking up." The UI thread cannot be blocked; if it is, the UI thread cannot update controls on your forms and respond to system messages. Responding to system messages is an important task of the UI thread; failing to do so makes your application appear locked up to the System. Not a good thing.
If you want to accomplish this (please don't) just create a Timer when you start doing work that, when it Ticks, indicates its time to stop pretending to do work.
Again, please don't do this.
I'd guess everything is running out of a single thread. The user probably invokes this algorithm by clicking on a button, or some such. This is handled by your main thread's message queue. Until this event handler returns, your app's GUI cannot update. It needs the message queue to be pumped on regular basis in order to stay responsive.
Sleeping is almost never a good idea, and definitely not a good idea in the GUI thread. I'm not going to recommend that you continue to use sleep and make your GUI responsive by calling Application.DoEvents.
Instead, you should run this algorithm in a background thread and when it completes it should signal so to the main thread.
You are about to commit some fairly common user interface bloopers:
Don't spam the user with minutiae, she's only interested in the result
Don't force the user to work as fast as you demand
Don't forbid the user to interact with your program when you are busy.
Instead:
Display results in a gadget like a ListBox to allow the user to review results at her pace
Keep a user interface interactive by using threads
Slow down time for your own benefit with a debugger
This depends on a lot of things, so its hard to give a concrete answer from what you've said. Still, here are some matters that might be relevant:
Are you doing this on a UI thread (e.g. the thread the form-button or UI event that triggered the work started on)? If so, it may be better to create a new thread to perform the work.
Why do you sleep at all? If the state related to the ongoing work is available to all relevant threads, can the observer not just observe this without the working thread sleeping? Perhaps the working thread could write an indicator of the current progress to a volatile or locked variable (it must be locked if it's larger than pointer size - e.g. int or an object - but not otherwise. If not locked, then being volatile will prevent cache inconsistency between CPUs, though this may not be a big deal). In this case you could have a forms timer (there are different timers in .Net with different purposes) check the status of that variable and update the UI to reflect the work being done, without the working thread needing to do anything. At most it may be beneficial to Yield() in the working thread on occasion, but its not likely that even this will be needed.

Use of Application.DoEvents()

Can Application.DoEvents() be used in C#?
Is this function a way to allow the GUI to catch up with the rest of the app, in much the same way that VB6's DoEvents does?
Hmya, the enduring mystique of DoEvents(). There's been an enormous amount of backlash against it, but nobody ever really explains why it is "bad". The same kind of wisdom as "don't mutate a struct". Erm, why does the runtime and the language supports mutating a struct if that's so bad? Same reason: you shoot yourself in the foot if you don't do it right. Easily. And doing it right requires knowing exactly what it does, which in the case of DoEvents() is definitely not easy to grok.
Right off the bat: almost any Windows Forms program actually contains a call to DoEvents(). It is cleverly disguised, however with a different name: ShowDialog(). It is DoEvents() that allows a dialog to be modal without it freezing the rest of the windows in the application.
Most programmers want to use DoEvents to stop their user interface from freezing when they write their own modal loop. It certainly does that; it dispatches Windows messages and gets any paint requests delivered. The problem however is that it isn't selective. It not only dispatches paint messages, it delivers everything else as well.
And there's a set of notifications that cause trouble. They come from about 3 feet in front of the monitor. The user could for example close the main window while the loop that calls DoEvents() is running. That works, user interface is gone. But your code didn't stop, it is still executing the loop. That's bad. Very, very bad.
There's more: The user could click the same menu item or button that causes the same loop to get started. Now you have two nested loops executing DoEvents(), the previous loop is suspended and the new loop is starting from scratch. That could work, but boy the odds are slim. Especially when the nested loop ends and the suspended one resumes, trying to finish a job that was already completed. If that doesn't bomb with an exception then surely the data is scrambled all to hell.
Back to ShowDialog(). It executes DoEvents(), but do note that it does something else. It disables all the windows in the application, other than the dialog. Now that 3-feet problem is solved, the user cannot do anything to mess up the logic. Both the close-the-window and start-the-job-again failure modes are solved. Or to put it another way, there is no way for the user to make your program run code in a different order. It will execute predictably, just like it did when you tested your code. It makes dialogs extremely annoying; who doesn't hate having a dialog active and not being able to copy and paste something from another window? But that's the price.
Which is what it takes to use DoEvents safely in your code. Setting the Enabled property of all your forms to false is a quick and efficient way to avoid problems. Of course, no programmer ever actually likes doing this. And doesn't. Which is why you shouldn't use DoEvents(). You should use threads. Even though they hand you a complete arsenal of ways to shoot your foot in colorful and inscrutable ways. But with the advantage that you only shoot your own foot; it won't (typically) let the user shoot hers.
The next versions of C# and VB.NET will provide a different gun with the new await and async keywords. Inspired in small part by the trouble caused by DoEvents and threads but in large part by WinRT's API design that requires you to keep your UI updated while an asynchronous operation is taking place. Like reading from a file.
It can be, but it's a hack.
See Is DoEvents Evil?.
Direct from the MSDN page that thedev referenced:
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 Microsoft cautions against its use.
Also, I consider it a hack because its behavior is unpredictable and side effect prone (this comes from experience trying to use DoEvents instead of spinning up a new thread or using background worker).
There is no machismo here - if it worked as a robust solution I would be all over it. However, trying to use DoEvents in .NET has caused me nothing but pain.
Yes, there is a static DoEvents method in the Application class in the System.Windows.Forms namespace. System.Windows.Forms.Application.DoEvents() can be used to process the messages waiting in the queue on the UI thread when performing a long-running task in the UI thread. This has the benefit of making the UI seem more responsive and not "locked up" while a long task is running. However, this is almost always NOT the best way to do things.
According to Microsoft calling DoEvents "...causes the current thread to be suspended while all waiting window messages are processed." If an event is triggered there is a potential for unexpected and intermittent bugs that are difficult to track down. If you have an extensive task it is far better to do it in a separate thread. Running long tasks in a separate thread allows them to be processed without interfering with the UI continuing to run smoothly. Look here for more details.
Here is an example of how to use DoEvents; note that Microsoft also provides a caution against using it.
From my experience I would advise great caution with using DoEvents in .NET. I experienced some very strange results when using DoEvents in a TabControl containing DataGridViews. On the other hand, if all you're dealing with is a small form with a progress bar then it might be OK.
The bottom line is: if you are going to use DoEvents, then you need to test it thoroughly before deploying your application.
Yes.
However, if you need to use Application.DoEvents, this is mostly an indication of a bad application design. Perhaps you'd like to do some work in a separate thread instead?
I saw jheriko's comment above and was initially agreeing that I couldn't find a way to avoid using DoEvents if you end up spinning your main UI thread waiting for a long running asynchronous piece of code on another thread to complete. But from Matthias's answer a simple Refresh of a small panel on my UI can replace the DoEvents (and avoid a nasty side effect).
More detail on my case ...
I was doing the following (as suggested here) to ensure that a progress bar type splash screen (How to display a "loading" overlay...) updated during a long running SQL command:
IAsyncResult asyncResult = sqlCmd.BeginExecuteNonQuery();
while (!asyncResult.IsCompleted) //UI thread needs to Wait for Async SQL command to return
{
System.Threading.Thread.Sleep(10);
Application.DoEvents(); //to make the UI responsive
}
The bad: For me calling DoEvents meant that mouse clicks were sometimes firing on forms behind my splash screen, even if I made it TopMost.
The good/answer: Replace the DoEvents line with a simple Refresh call to a small panel in the centre of my splash screen, FormSplash.Panel1.Refresh(). The UI updates nicely and the DoEvents weirdness others have warned of was gone.
I've seen many commercial applications, using the "DoEvents-Hack". Especially when rendering comes into play, I often see this:
while(running)
{
Render();
Application.DoEvents();
}
They all know about the evil of that method. However, they use the hack, because they don't know any other solution. Here are some approaches taken from a blog post by Tom Miller:
Set your form to have all drawing occur in WmPaint, and do your rendering there. Before the end of the OnPaint method, make sure you do a this.Invalidate(); This will cause the OnPaint method to be fired again immediately.
P/Invoke into the Win32 API and call PeekMessage/TranslateMessage/DispatchMessage. (Doevents actually does something similar, but you can do this without the extra allocations).
Write your own forms class that is a small wrapper around CreateWindowEx, and give yourself complete control over the message loop.
-Decide that the DoEvents method works fine for you and stick with it.
Check out the MSDN Documentation for the Application.DoEvents method.
The DoEvents does allow the user to click around or type and trigger other events, and background threads are a better approach.
However, there are still cases where you may run into issues that require flushing event messages. I ran into a problem where the RichTextBox control was ignoring the ScrollToCaret() method when the control had messages in queue to process.
The following code blocks all user input while executing DoEvents:
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace Integrative.Desktop.Common
{
static class NativeMethods
{
#region Block input
[DllImport("user32.dll", EntryPoint = "BlockInput")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool BlockInput([MarshalAs(UnmanagedType.Bool)] bool fBlockIt);
public static void HoldUser()
{
BlockInput(true);
}
public static void ReleaseUser()
{
BlockInput(false);
}
public static void DoEventsBlockingInput()
{
HoldUser();
Application.DoEvents();
ReleaseUser();
}
#endregion
}
}
Application.DoEvents can create problems, if something other than graphics processing is put in the message queue.
It can be useful for updating progress bars and notifying the user of progress in something like MainForm construction and loading, if that takes a while.
In a recent application I've made, I used DoEvents to update some labels on a Loading Screen every time a block of code is executed in the constructor of my MainForm. The UI thread was, in this case, occupied with sending an email on a SMTP server that didn't support SendAsync() calls. I could probably have created a different thread with Begin() and End() methods and called a Send() from their, but that method is error-prone and I would prefer the Main Form of my application not throwing exceptions during construction.

Categories