using System;
using System.Threading;
using System.Windows.Forms;
namespace Threading.Utils
{
public static class Threading
{
[ThreadStatic] private static bool isInSafeCall;
[ThreadStatic] private static bool isInSeparatedThread;
private readonly static AutoResetEvent ShowExceptionLock = new AutoResetEvent(true);
private const string PRODUCT_LABEL = "ProductLabel";
/// Executes a Safe Call within a new Thread
public static void ThreadedSafeCall(this IWin32Window window, Action method)
{
window.ThreadedCall(
()=> window.SafeCall(method)
);
}
/// Executes a Call within a queued worker process
public static void ThreadedCall(this IWin32Window window, Action method)
{
var ctrl = window as Control;
bool createdState = ctrl == null || ctrl.Created;
// Do not force a new thread when a the caller already in a new thread
// or the control has not even been created.
if (!isInSeparatedThread && createdState)
{
var thread = new Thread(() =>
{
isInSeparatedThread = true;
method();
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
else
{
// A Thread already started
method();
}
}
///
/// Executes the Action Method in a safe way, in that exceptions are handled.
///
public static void SafeCall(this IWin32Window window, Action method)
{
// If the call has already been assured, so only executed the method inside
if (isInSafeCall)
{
method();
return;
}
try
{
isInSafeCall = true;
method();
}
catch (Exception exception)
{
var ctrl = window as Control;
if (ctrl != null)
ctrl.InvokeIfRequired(() => window.ShowException(null, exception));
else
window.ShowException(null, exception);
}
finally
{
isInSafeCall = false;
}
}
///
/// Shows the exception.
///
public static void ShowException(this IWin32Window parentWindow, string preText, Exception exception)
{
parentWindow.Singleton(ShowExceptionLock, () =>
{
string message = !string.IsNullOrEmpty(preText)
? string.Concat(preText, "\n\n", exception.Message)
: exception.Message;
MessageBox.Show(parentWindow, message, PRODUCT_LABEL, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
});
}
///
/// Declares that a method is only called once.
/// Second call's from other threads to the method will return immidiatly.
///
/// The window.
/// The locking.
/// The method.
public static void Singleton(this IWin32Window window, AutoResetEvent locking, Action method)
{
// Return immidiatly, if the event could not aquired.
if (!locking.WaitOne(0))
return;
try
{
method();
}
finally
{
locking.Set();
}
}
///
/// Invokes the method if required.
///
/// The window.
/// The method.
public static void InvokeIfRequired(this Control window, Action method)
{
if (!window.InvokeRequired)
method();
else
window.Invoke(new MethodInvoker(() => method()));
}
///
/// Invokes the method if required.
///
/// The window.
/// The method.
public static void InvokeAsyncIfRequired(this Control window, Action method)
{
if (!window.InvokeRequired)
method();
else
window.BeginInvoke(new MethodInvoker(() => method()));
}
}
}