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())); } } }