110 lines
2.9 KiB
C#
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
|
|
}
|
|
}
|