Я встречаюсь с проблемой с приложением 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()
?
Попробуйте вот это:
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
!
Вы, вероятно, выполняете этот код до того, как форма будет показана.
Следовательно, InvokeRequired
возвращает false
.
Я полагаю, что здесь происходит то, что этот код выполняется до того, как Форма
когда-либо будет показана.
Когда форма
создается в .Net, она не сразу становится привязанной к определенному потоку. Только при выполнении определенных операций, таких как показ или захват ручки, она приобретает сродство. Пока этого не произошло, InvokeRequired
не может работать правильно.
В данном конкретном случае родство не установлено, и родительского элемента управления не существует, поэтому InvokeRequired
возвращает false, поскольку не может определить исходный поток.
Способ исправить это - установить родство для вашего элемента управления при его создании в потоке пользовательского интерфейса. Лучший способ сделать это - просто запросить у элемента управления его свойство handle.
var notUsed = control.Handle;
Вы, вероятно, дойдете до этого кода до того, как форма будет показана, и, следовательно, дескриптор окна не был создан.
Вы можете добавить этот код перед своим кодом, и все должно быть хорошо:
if (! this.IsHandleCreated)
this.CreateHandle();
Изменить: Есть еще одна проблема с вашим кодом. После отображения формы вы не можете снова вызвать ShowDialog (). Вы получите исключение недопустимой операции. Вы можете изменить этот метод, как предлагали другие.
Возможно, вам лучше вызвать ShowDialog () непосредственно из вызывающего класса и использовать другой метод для BringToFront () или что-то в этом роде ...
Я также думаю, что 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 из другого потока
Вы всегда можете попробовать протестировать другой элемент управления.
Например, вы можете получить доступ к коллекциям Application.Forms
public Control GetControlToInvokeAgainst()
{
if(Application.Forms.Count > 0)
{
return Application.Forms[0];
}
return null;
}
Затем в своем методе DisplayDialog () вызовите GetControlToInvokeAgainst () и проверьте значение null, прежде чем пытаться выполнить вызов, требуемый для вызова.
Скорее всего, дескриптор элемента управления еще не создан, и в этом случае Control.InvokeRequired
возвращает false
.
Проверьте свойство Control.IsHandleCreated
, чтобы узнать, так ли это.