2010-04-19 12 views
6

Czytałem, że wersja C# jest w następujący sposób:Jak zrobić "DoEvents" w WPF?

Application.Current.Dispatcher.Invoke(
      DispatcherPriority.Background, 
      new Action(delegate { })); 

Jednak nie mogę dowiedzieć się, jak umieścić pustą delegata w VB.NET, ponieważ VB.NET nie wydaje się wspierać metody anonimowe. Pomysły?

Edycja: ewentualnie to?

Application.Current.Dispatcher.Invoke(
    DispatcherPriority.Background, 
    New Action(Sub() 

      End Sub)) 
+0

DoEvents? Sądzę, że używali DoEvents z powrotem w VB6, zanim ludzie zorientowali się, że aplikacja może mieć coś więcej niż tylko wątek interfejsu użytkownika. – Will

+0

Cóż, nowoczesną konwencją jest użycie Thread.Sleep (1) lub podobnego, ale to nie działa, gdy trzeba tymczasowo wyskoczyć z wątku, aby umożliwić aktualizację interfejsu i pozostawać w środku pętli przetwarzania WPF. – NibblyPig

+1

@SLC: Jeśli przetwarzasz dane w innym wątku, nie powinieneś mówić interfejsowi, aby aktualizował się (w zwykły sposób odświeżania). –

Odpowiedz

6

VB.NET obsługuje anonimowych delegatów, ale tylko jako funkcje pojedynczego rachunku. (Anonimowe funkcje wielu oświadczeń i anonimowe Sub s zostały dodane do VB10 w .NET 4)

Aby zapewnić kontekst, DoEvents został zaprojektowany, aby umożliwić środowisku jednowątkowym aktualizację interfejsu użytkownika i przetwarzanie innych komunikatów systemu Windows podczas pracy gotowe. Nie powinno być żadnego pożytku z wywoływania DoEvents (lub, jak to tutaj robisz, robiąc to pośrednio, wykonując funkcję "zerową" w module rozsyłającym) z innego wątku, ponieważ wątek interfejsu użytkownika powinien sam się aktualizować.

W interesie odpowiadając na pytanie, choć najprostszym rozwiązaniem byłoby coś takiego:

Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, _ 
    New Action(Function() 7)) 

Ale znowu, nie widzę, co by to rzeczywiście osiągnąć.

Jeśli to, czego szukasz, to po prostu jak wykonać kod w wątku UI (np. Control.Invoke z formularzy Windows), to Dispatcher.Invoke (którego używasz) jest poprawne, po prostu musisz Przetłumacz swoje inline anonimowe metody na dyskretne funkcje i przekazuj je jako delegatów. Być może niektóre z nich mogą uciec z powodu anonimowości. Na przykład, jeśli wszystko co robisz jest aktualizowanie pasek postępu, można zrobić:

Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, _ 
    New Action(Function() progressBar.Value = 100)) 

To działa, ponieważ wszystkie zadania zwrotu wartości, który został zapisany w lewej stronie przypisania. Państwo nie może jednak, po prostu zadzwoń sub tak (dodaje się nie skompiluje chyba SomeFunctionName Zwraca wartości):

Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, _ 
    New Action(Function() SomeFunctionName(params))) 

Innymi słowy, każdy z anonimowych delegatów, które są w kodzie C#, które albo :

  • więcej niż jeden rachunek
  • nie zwracają wartość (co oznacza to tylko jedno wywołanie metody, a nie funkcja)

Pokochasz więc h ave do tworzenia funkcji dla tych i przekazywać delegatów do tych funkcji, zamiast wpisywania kodu, jak masz w C#.

+0

Interfejs użytkownika może być aktualizowany tylko wtedy, gdy ma szansę na to, co jest na końcu funkcji. Z tego powodu twoja aplikacja przestaje odpowiadać, jeśli umieścisz w niej pętlę, a nawet ze snem wątku nie zaktualizuje komponentów interfejsu użytkownika w pętli bez wywoływania Invoke w formularzach Windows, aby wymusić przejście do innego wątku. Spekuluję, że to jest to samo. – NibblyPig

+0

Możesz zmienić Function() na Sub() i po prostu mieć puste Sub(), jak spekulowałem w mojej edycji, ponieważ właśnie potwierdziłem to w kodzie i wygląda na to, że działa. – NibblyPig

+3

@SLC: Jest to prawdą tylko wtedy, gdy to, co robisz * ma miejsce w wątku UI *. Jeśli kod jest wykonywany w innym wątku, nie jest to konieczne. ** Jeśli to, co robisz * jest * wykonywane w wątku UI i trwa to wystarczająco długo, aby wymagać jawnej aktualizacji interfejsu, to powinno zostać przeniesione do innego wątku. ** –

0

Użyj słowa kluczowego Function:

Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, New Action(Function() Do ... End Function)) 
+0

Problem polega na tym, że akcja nic nie robi, więc co mogę tam umieścić, to jest "nic "? Również funkcja zwraca zmienną. – NibblyPig

+0

Czy kompiluje się, jeśli po prostu usunąć kropki? O jakiej wersji VB/.NET mówimy tutaj? –

1

Masz tu dwa pytania, więc zamierzam dodać dwie odpowiedzi. Tutaj odpowiadam "jak zrobić DoEvents w WPF".Bea Stollnitz Obejmuje to na her blog, a oto kod w VB:

publicShared Sub WaitForPriority(priority As DispatcherPriority) 
    Dim frame As New DispatcherFrame() 
    Dim dispatcherOperation As DispatcherOperation = Dispatcher.CurrentDispatcher.BeginInvoke(priority, New DispatcherOperationCallback(ExitFrameOperation), frame) 
    Dispatcher.PushFrame(frame) 
    If dispatcherOperation.Status <> DispatcherOperationStatus.Completed Then 
     dispatcherOperation.Abort() 
    End If 
End Sub 

Private Shared Function ExitFrameOperation(obj As Object) As Object 
    (DirectCast(obj, DispatcherFrame)).[Continue] = False 
    Return Nothing 
End Function 
3

Można po prostu wywołać tę metodę, jeśli chcesz coś być odświeżane na interfejsie:

System.Windows.Forms.Application.DoEvents 

Używamy go na nasze okna WPF i aplikacje XBAP.

0

lub po prostu użyć dyspozytora, aby sobie DoEvents() dla WPF:

'The WPF equivalent of DoEvents!! 
Public Sub DoEvents() 
    Dispatcher.Invoke(New Action(Function() 
            Return Nothing 
           End Function), DispatcherPriority.ContextIdle, Nothing) 
End Sub