How to Invoke() when I have no Control available
I'm writing a connection handler (a dialog to request username and password). The code is a handler that shows a dialog. This code could be called from a thread, so I need to Invoke()
if InvokeRequired
.
In a ideal situation I can initialize then handler with a Control
to do InvokeRequired
, but sometimes the Control could be null. Is it possible? How could I implement the code? Is the following correct?
public class GuiCredentialsHandler
{
// control used to invoke if needed
private static Control mInvokeControl;
/// <summary>
/// Initialize a GetCredentials handler for current process.
/// This method should be always called from the main thread, for
/// a correctly handling for invokes (when the handler is called
/// from a thread).
/// </summary>
/// <param name="parentControl">Application top form.
/// Can be null if unknown</param>
public static void Initialize(Control parentControl)
{
if (parentControl != null)
{
mInvokeControl = parentControl;
}
else
{
mInvokeControl = new Control();
// force to create window handle
mInvokeControl.CreateControl();
}
}
public static Credentials GetCredentials()
{
if (mInvokeControl.InvokeRequired)
{
return mInvokeControl.Invoke(
new GetCredentialsDelegate(DoGetCredentials), null)
as Credentials;
}
else
{
return DoGetCredentials();
}
}
private static Credentials DoGetCredentials()
{
// the code stuff goes here
}
}
My questions are:
开发者_运维百科- What happens if I pass a null control to the
InitializeMethod()
- If the Initialize() method is executed in the UIThread, will the code work later?
- What is the recommended pattern if you havn't got any control to test
InvokeRequired
?
Thanks in advance
EDIT: Doing some tests, I have realized that if I pass null to Initialize()
, the control is not running in the UI thread so the InvokeRequired seems to return false. Always. So my question is, how can I perform a real (fiable) Invoke when I have no control?
EDIT2: Doing mInvokeControl.CreateControl()
fixs the issue.
Implement ISynchronizeInvoke on that class instead. Here is an example:
public class GuiCredentialsHandler : ISynchronizeInvoke
{
//....
private readonly System.Threading.SynchronizationContext _currentContext = System.Threading.SynchronizationContext.Current;
private readonly System.Threading.Thread _mainThread = System.Threading.Thread.CurrentThread;
private readonly object _invokeLocker = new object();
//....
#region ISynchronizeInvoke Members
public bool InvokeRequired
{
get
{
return System.Threading.Thread.CurrentThread.ManagedThreadId != this._mainThread.ManagedThreadId;
}
}
/// <summary>
/// This method is not supported!
/// </summary>
/// <param name="method"></param>
/// <param name="args"></param>
/// <returns></returns>
[Obsolete("This method is not supported!", true)]
public IAsyncResult BeginInvoke(Delegate method, object[] args)
{
throw new NotSupportedException("The method or operation is not implemented.");
}
/// <summary>
/// This method is not supported!
/// </summary>
/// <param name="method"></param>
/// <param name="args"></param>
/// <returns></returns>
[Obsolete("This method is not supported!", true)]
public object EndInvoke(IAsyncResult result)
{
throw new NotSupportedException("The method or operation is not implemented.");
}
public object Invoke(Delegate method, object[] args)
{
if (method == null)
{
throw new ArgumentNullException("method");
}
lock (_invokeLocker)
{
object objectToGet = null;
SendOrPostCallback invoker = new SendOrPostCallback(
delegate(object data)
{
objectToGet = method.DynamicInvoke(args);
});
_currentContext.Send(new SendOrPostCallback(invoker), method.Target);
return objectToGet;
}
}
public object Invoke(Delegate method)
{
return Invoke(method, null);
}
#endregion//ISynchronizeInvoke Members
}
Note: Because of the class implementation it uses System.Threading.SynchronizationContext.Current
so you can use it in WindowsForms
or wpf
but not a Console application because the System.Threading.SynchronizationContext.Current
is null.
A simple solution is to create an invisible control in the main thread on which your worker threads can call Invoke
.
精彩评论