using System; using System.Reflection; using System.Windows.Forms; using JD.Kernel.StaticHelpers; namespace JD.Threading.Dispatch { /// /// Must be created on the destination UI thread to work. /// internal class WindowsFormsThreadDispatchStrategy : IThreadDispatchStrategy { #region Variables private readonly Control m_control; #endregion #region Constructor public WindowsFormsThreadDispatchStrategy() { // WindowsFormsSynchronizationContext manages a special control that is always available for marshalling // Works around limitations of normal Control.Invoke (never knowing when the control is going to be disposed) // Sadly, it's not publicly available so we use reflection to get to it WindowsFormsSynchronizationContext syncContext = new WindowsFormsSynchronizationContext(); m_control = (Control)syncContext.GetType().GetField("controlToSendTo", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(syncContext); Throw.InvalidOperationIf(m_control == null, "Could not create WindowsFormsThreadDispatchStrategy"); } #endregion #region Properties public bool InvokeRequired { get { return m_control.InvokeRequired; } } bool IThreadDispatchStrategy.LongOperationInvokeRequired { get { return InvokeRequired; } } #endregion #region Methods public void Dispatch(System.Action action) { if (InvokeRequired) { DoControlInvoke(action); } else { action(); } } public void DispatchAsync(System.Action action, bool forceAsync) { if (InvokeRequired || forceAsync) { m_control.BeginInvoke(action); } else { action(); } } public void DoLongOperation(System.Action action) { Dispatch(action); } public void DoLongOperationAsync(System.Action action) { DispatchAsync(action, false); } private void DoControlInvoke(System.Action action) { Exception ex = null; m_control.Invoke(new System.Action(() => { try { action(); } catch (Exception e) { ex = e; } })); if (ex != null) { throw new Exception("An exception occurred while invoking an action on the UI thread", ex); } } #endregion } }