开发者

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:

开发者_运维百科
  1. What happens if I pass a null control to the InitializeMethod()
  2. If the Initialize() method is executed in the UIThread, will the code work later?
  3. 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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜