JD2022-TU1/main/tools/framework/JD.Threading/Dispatch/WindowsFormsThreadDispatchStrategy.cs

110 lines
2.9 KiB
C#

using System;
using System.Reflection;
using System.Windows.Forms;
using JD.Kernel.StaticHelpers;
namespace JD.Threading.Dispatch
{
/// <summary>
/// Must be created on the destination UI thread to work.
/// </summary>
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
}
}