Что случилось с моим перекрестным потоком звонят в Windows Forms?

Я встречаюсь с проблемой с приложением Windows Forms.

Форма должна быть отображена от другого потока. Таким образом в классе формы, у меня есть следующий код:

private delegate void DisplayDialogCallback();

public void DisplayDialog()
{
    if (this.InvokeRequired)
    {
        this.Invoke(new DisplayDialogCallback(DisplayDialog));
    }
    else
    {
        this.ShowDialog();
    }
}

Теперь, каждый раз я выполняю это, InvalidOperationException брошен на строку this.ShowDialog();:

"Перекрестный распараллельте операцию, не допустимую: Управляйте 'SampleForm', к которому получают доступ от потока кроме потока, на котором он был создан".

Что случилось с этой частью кода? Разве это не допустимый способ выполнить вызовы перекрестного потока? Есть ли что-то специальное с ShowDialog()?

9
задан Arseni Mourzenko 15 June 2010 в 16:19
поделиться

7 ответов

Попробуйте вот это:

private delegate void DisplayDialogCallback();

public void DisplayDialog()
{
    if (this.InvokeRequired)
    {
        this.Invoke(new DisplayDialogCallback(DisplayDialog));
    }
    else
    {
        if (this.Handle != (IntPtr)0) // you can also use: this.IsHandleCreated
        {
            this.ShowDialog();

            if (this.CanFocus)
            {
                this.Focus();
            }
        }
        else
        {
            // Handle the error
        }
    }
}

Обратите внимание, что InvokeRequired возвращает

true, если хэндл элемента управления был создан в другом потоке, чем вызывающего потока (что указывает на то, что вы должны обращаться к элементу управления через метод invoke); в противном случае - false.

и поэтому, если элемент управления не был создан, возвращаемое значение будет false!

4
ответ дан 4 December 2019 в 11:39
поделиться

Вы, вероятно, выполняете этот код до того, как форма будет показана.
Следовательно, InvokeRequired возвращает false .

8
ответ дан 4 December 2019 в 11:39
поделиться

Я полагаю, что здесь происходит то, что этот код выполняется до того, как Форма когда-либо будет показана.

Когда форма создается в .Net, она не сразу становится привязанной к определенному потоку. Только при выполнении определенных операций, таких как показ или захват ручки, она приобретает сродство. Пока этого не произошло, InvokeRequired не может работать правильно.

В данном конкретном случае родство не установлено, и родительского элемента управления не существует, поэтому InvokeRequired возвращает false, поскольку не может определить исходный поток.

Способ исправить это - установить родство для вашего элемента управления при его создании в потоке пользовательского интерфейса. Лучший способ сделать это - просто запросить у элемента управления его свойство handle.

var notUsed = control.Handle;
5
ответ дан 4 December 2019 в 11:39
поделиться

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

Вы можете добавить этот код перед своим кодом, и все должно быть хорошо:

if (! this.IsHandleCreated)
   this.CreateHandle();

Изменить: Есть еще одна проблема с вашим кодом. После отображения формы вы не можете снова вызвать ShowDialog (). Вы получите исключение недопустимой операции. Вы можете изменить этот метод, как предлагали другие.

Возможно, вам лучше вызвать ShowDialog () непосредственно из вызывающего класса и использовать другой метод для BringToFront () или что-то в этом роде ...

1
ответ дан 4 December 2019 в 11:39
поделиться

Я также думаю, что SLaks прав. Из msdn (http://msdn.microsoft.com/en-us/library/system.windows.forms.control.invokerequired.aspx):

Если подходящий хэндл не найден, метод InvokeRequired возвращает false.

Если это возможно в вашем случае, я бы попробовал объединить создание и показ элемента управления в одном методе, т.е.:

public DisplayDialog static Show()
{
  var result = new DisplayDialog; //possibly cache instance of the dialog if needed, but this could be tricky
  result.ShowDialog(); 
  return result;
}

вы можете вызвать Show из другого потока

0
ответ дан 4 December 2019 в 11:39
поделиться

Вы всегда можете попробовать протестировать другой элемент управления.

Например, вы можете получить доступ к коллекциям Application.Forms

public Control GetControlToInvokeAgainst()
{
    if(Application.Forms.Count > 0)
    {
        return Application.Forms[0];
    }
    return null;
}

Затем в своем методе DisplayDialog () вызовите GetControlToInvokeAgainst () и проверьте значение null, прежде чем пытаться выполнить вызов, требуемый для вызова.

0
ответ дан 4 December 2019 в 11:39
поделиться

Скорее всего, дескриптор элемента управления еще не создан, и в этом случае Control.InvokeRequired возвращает false .

Проверьте свойство Control.IsHandleCreated , чтобы узнать, так ли это.

0
ответ дан 4 December 2019 в 11:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: