Form.Show () вызывает исключение InvalidOperationException в Visual Studio 2010, которого не было в 2008 году - PullRequest
1 голос
/ 07 июня 2011

У меня есть некоторый код, который принимает объект формы (winforms) и вызывает form.Show () в выделенном потоке (он вращает новый поток).Это отлично работало в Visual Studio 2008 (framework 3.5).Теперь я перенесен на 2010 год, и это вызывает сбой с InvalodOperationException: «Межпотоковая операция недопустима: доступ к элементу управления» выполняется из потока, отличного от потока, в котором он был создан ».

(конечно, половина наших файлов проверенадля миграции, и вся команда ждет ...)

Вот некоторый код (это бегущий код, так что мне не хватает некоторого избыточного уровня детализации):

    private void ShowForm(object container)
    {
        FormContainer formContainer = (FormContainer)container;
        Process sboProcess = GetSboProcess();
        if (sboProcess != null)
        {
            WindowWrapper MyWindow = new WindowWrapper(sboProcess.MainWindowHandle);
            if (formContainer.ShowDialog)
            {
                formContainer.Form.ShowDialog(MyWindow);
            }
            else
            {
                //formContainer.Form.Invoke((MethodInvoker)delegate() { formContainer.Form.Show(MyWindow); });
                formContainer.Form.Show(MyWindow);
                //Run thread while form is opened:
                System.Windows.Forms.Application.Run(formContainer.Form);
            }
        }
    }



public class FormContainer
{
    private readonly Form form;
    private readonly bool showDialog;

    public FormContainer(Form form, bool showDialog)
    {
        this.form = form;
        this.showDialog = showDialog;
    }

    public bool ShowDialog
    {
        get { return showDialog; }
    }

    public Form Form
    {
        get { return form; }
    }

}

 public class WindowWrapper : IWin32Window
{
    private readonly IntPtr handle;

    public WindowWrapper(IntPtr handle)
    {
        this.handle = handle;
    }

    #region Implementation of IWin32Window

    /// <summary>
    ///                     Gets the handle to the window represented by the implementer.
    /// </summary>
    /// <returns>
    ///                     A handle to the window represented by the implementer.
    /// </returns>
    /// <filterpriority>1</filterpriority>
    public IntPtr Handle
    {
        get { return handle; }
    }

    #endregion
}

Кто-нибудь с идеей?

Спасибо,

Ашер

1 Ответ

3 голосов
/ 07 июня 2011

в предложении;выделенный поток должен перезвонить потоку пользовательского интерфейса, которому принадлежит форма.Межпоточные операции пользовательского интерфейса недопустимы, поскольку существуют определенные операции, которые могут привести к отключению элемента управления пользовательского интерфейса от обработчика сообщений Windows.Это плохо, потому что тогда Windows не может сказать окну делать что-либо, включая рисование самого себя, перемещение или даже закрытие.Окно становится «мошенническим», и все, что Windows может сделать, это завершить весь процесс, который породил окно.

Вызов метода формы может быть синхронной или асинхронной операцией, но в любом случае его необходимо поставить в очередь.для выполнения потоком пользовательского интерфейса.

Вот способ сделать вызовы из фоновых потоков SEEM, как если бы они выполнялись фоновым потоком, без нарушения правил многопоточности:

//in your form class
public new void Show()
{
   if(!InvokeRequired)
      base.Show();
   else
      this.Invoke((MethodInvoker)(()=>base.Show()));
}

Поймите, что вы не можете иметь дело с формой как с базовым классом System.Windows.Form;это должен быть конкретный класс формы, который вы создаете.В противном случае скрытие метода игнорируется, и базовая реализация используется по умолчанию.

Настраивая его таким образом, всякий раз, когда действие может быть запущено из фонового потока, вы избегаете операций многопоточности.При желании вы можете изменить этот метод для асинхронного запуска, вызвав BeginInvoke () для элемента управления вместо Invoke (), но поскольку вызов Show () обычно выполняется синхронно, я бы придерживался Invoke.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...