2010-06-15 11 views
9

Występuje problem z aplikacją Windows Forms.Co jest nie tak z moim wywołaniem krzyżowym w Windows Forms?

Formularz musi być wyświetlany z innego wątku. Więc w klasie formularza, mam następujący kod:

private delegate void DisplayDialogCallback(); 

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

Teraz za każdym razem, biegnę, aktualny InvalidOperationException jest rzucony na linii this.ShowDialog();:

„operacja Cross wątek nie ważne: Kontroli "SampleForm" dostępny z wątku innego niż wątek, na którym został utworzony. "

Co jest nie tak z tym kodem? Czy nie jest to prawidłowy sposób nawiązywania połączeń z wątkami krzyżowymi? Czy jest coś specjalnego z ShowDialog()?

+3

Z ciekawości, co ma IsHandleCreated show? –

+0

@Marc Gravell: IsHandleCreated jest fałszywe. Naturalnie, jak powiedziało kilka osób, kod jest wykonywany przed wyświetleniem formularza. –

Odpowiedz

4

Spróbuj tego:

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 
     } 
    } 
} 

Uwaga InvokeRequired powraca

true jeśli obsługiwać kontrolki została stworzony na innym wątku niż wywołujący wątek (indi o tym, że musisz wykonywać wywołania do kontroli poprzez metodę invoke); w przeciwnym razie false.

, a zatem, jeśli kontrola nie została utworzona, zwróconą wartością będzie false!

8

Prawdopodobnie wykonujesz ten kod przed wyświetleniem formularza.
Dlatego InvokeRequired wraca false.

5

Wierzę, że tutaj dzieje się tak, że ten kod jest uruchamiany, zanim zostanie wyświetlony kod Form.

Po utworzeniu Form w .Net nie uzyskuje natychmiast powinowactwa do określonego wątku. Tylko wtedy, gdy wykonywane są pewne operacje, takie jak pokazywanie lub chwytanie klamki, zyskuje ona na powinowactwie. Zanim to nastąpi, trudno jest InvokeRequired działać poprawnie.

W tym szczególnym przypadku nie jest ustalone żadne powinowactwo i nie istnieje kontrola rodzica, więc InvokeRequired zwraca wartość false, ponieważ nie może ustalić oryginalnego wątku.

Sposobem naprawienia tego jest ustanowienie powinowactwa do kontroli, gdy jest tworzone w wątku interfejsu użytkownika. Najlepszym sposobem na zrobienie tego jest poproszenie kontrolki o jej własność.

var notUsed = control.Handle; 
+0

Dziwne, ale uzyskanie 'control.Handle' nic nie zmienia: wyjątek jest nadal zgłaszany. Zamiast tego sugestia Lorenzo działa dobrze. IMHO, jest to spowodowane faktem, że kompilator właśnie usuwa 'var notUsed = control.Handle;' line, podczas gdy zmienna 'notUsed' nie jest używana. –

0

Zawsze możesz wypróbować testowanie pod inną kontrolą.

Na przykład, można uzyskać dostęp do Application.Forms zbiory

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

Następnie w metodzie swojej DisplayDialog() wywołać GetControlToInvokeAgainst() i test dla wartości null przed próbą wykonania invokerequired połączenia.

0

Najprawdopodobniej uchwyt formantu nie jest jeszcze utworzony, w takim przypadku Control.InvokeRequired zwraca false.

Sprawdź właściwość Control.IsHandleCreated, aby sprawdzić, czy tak jest.

0

Też myślę, że Slaks jest poprawny. Od msdn (http://msdn.microsoft.com/en-us/library/system.windows.forms.control.invokerequired.aspx):

Jeśli nie można znaleźć odpowiedniego uchwytu, metoda InvokeRequired zwraca wartość false.

Jeśli jest to możliwe w twoim przypadku, spróbuję połączyć tworzenie i pokazywanie kontroli w jednej metodzie, tj.:

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; 
} 

można nazwać Pokaż z innego wątku

1

Prawdopodobnie dostaniesz się do tego kodu przed wyświetleniem formularza i dlatego uchwyt okna nie został utworzony.

Możesz dodać ten kod przed kodem i wszystko powinno być dobrze:

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

Edycja: Jest jeszcze inny problem z kodem. Po wyświetleniu formularza nie można ponownie wywołać ShowDialog(). Otrzymasz wyjątek dotyczący nieprawidłowej operacji. Możesz zmodyfikować tę metodę, jak proponowali inni.

Może być lepiej służył wywołanie ShowDialog() bezpośrednio z klasy wywołującego i mają inny sposób BringToFront() lub coś w tym stylu ...