How to Invoke() when I have no Control available

半世苍凉 提交于 2019-12-02 08:08:46

问题


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.


回答1:


A simple solution is to create an invisible control in the main thread on which your worker threads can call Invoke.




回答2:


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.



来源:https://stackoverflow.com/questions/6708765/how-to-invoke-when-i-have-no-control-available

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!