Как вызвать (), когда у меня нет доступных элементов управления - PullRequest
1 голос
/ 15 июля 2011

Я пишу обработчик соединения (диалог для запроса имени пользователя и пароля). Код является обработчиком, который показывает диалог. Этот код может быть вызван из потока, поэтому мне нужно Invoke(), если InvokeRequired.

В идеальной ситуации я могу затем инициализировать обработчик с Control, чтобы сделать InvokeRequired, но иногда Control может быть нулевым. Является ли это возможным? Как я мог реализовать код? Правильно ли следующее?

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
    }

}

Мои вопросы:

  1. Что произойдет, если я передам нулевой элемент управления InitializeMethod()
  2. Если метод Initialize () выполняется в UIThread, будет ли код работать позже?
  3. Какой шаблон рекомендуется, если у вас нет контроля для проверки InvokeRequired?

Заранее спасибо


EDIT : выполняя некоторые тесты, я понял, что, если я передаю ноль в Initialize(), элемент управления не запускается в потоке пользовательского интерфейса, поэтому InvokeRequired, похоже, возвращает false. Всегда. Поэтому мой вопрос: как я могу выполнить настоящий (надежный) Invoke, когда у меня нет контроля?


EDIT2 : Выполнение mInvokeControl.CreateControl() устраняет проблему.

Ответы [ 2 ]

3 голосов
/ 15 июля 2011

Реализовать ISynchronizeInvoke вместо этого класса. Вот пример:

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

}

Примечание. Из-за реализации класса он использует System.Threading.SynchronizationContext.Current, поэтому вы можете использовать его в WindowsForms или wpf, но не в консольном приложении, поскольку System.Threading.SynchronizationContext.Current равно нулю.

1 голос
/ 15 июля 2011

Простое решение - создать невидимый элемент управления в главном потоке, в котором ваши рабочие потоки могут вызывать Invoke.

...