2012-10-17 8 views
10

W WinFormach wszystkie kontrolki mają właściwość InvokeRequired, która zwraca wartość true, gdybym musiał zadzwonić. [Begin] Wywołaj kontrolkę, aby ją zmodyfikować.Prawidłowe użycie (lub nieużywanie) Dispatchera.CheckAccess()

W WPF istnieje podobna konstrukcja w postaci DispatcherObject.CheckAccess() i Dispatcher.CheckAccess(), ale jestem przerażony atrybutem EditorBrowsable(EditorBrowsableState.Never). Kiedy wyłączam przeglądanie tego edytora, używam go w znaczeniu "Powinieneś , a nie robić to." Nie, naprawdę .Jeśli jest to wymagane, rozwiąż swój natychmiastowy problem, źle zaprojektowałeś swoje rozwiązanie dla swojego nadrzędnego problemu. " Z drugiej strony jedyną alternatywą, którą znalazłem (i, w rzeczywistości, moje oryginalne rozwiązanie) jest Thread.CurrentThread.ManagedThreadId == 1. (To straszne. I to nie działa w ogólnym przypadku. Wiem. To działa dla moich ograniczonych zastosowań, choć.)

MSDNdocumentation milczy na temat obecności i rozumowania za atrybut EditorBrowsable. Czy rzeczywiście oznacza to "nie używaj tego", tak jakby to było, gdybym to napisał, czy też ma jakieś inne, mniej restrykcyjne znaczenie?

+0

Wydawało się, że kilka osób z MSFT odpowiedziało w tym poście. http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/bd0e6f6c-cadd-48f1-8e1a-163c2f17e4ca/ Wydaje się, że "EditorBrowsableState.Advanced" mogło być bardziej odpowiednie, ale nie wydaje się być jakimkolwiek technicznym powodem, dlaczego nie powinno się go nazywać (przynajmniej z tego wątku). – keyboardP

Odpowiedz

15

W WPF można nazwać Dispatcher.Invoke niezależnie od bieżącego wątku i będzie obsługiwać połączenia odpowiednio - jeśli już jesteś na właściwym wątku, będzie to po prostu powołać swój kod i wykorzystuje CheckAccess obsłużyć to zachowanie.

Dla bieżącego wątku nie ma znaczenia: BeginInvoke jest zawsze asyncroniczny, a kolejność wykonywania zależy od priorytetu pozycji dodawanej do kolejki wysyłającego.

Jeśli w ogóle nie powinieneś używać tej metody, nie będzie ona publiczna: celem tego atrybutu jest jedynie ukrycie użytkownika przed mechanizmami takimi jak Intellisense i inne edytory-przeglądarki. Zwykle nie musisz samodzielnie używać Dispatcher.CheckAccess(), co prawdopodobnie oznacza, że ​​jest on oznaczony jako niemożliwy do przeglądania, ale mądrość tego można jedynie zgadywać (chyba, że ​​Eric Lippert patrzy ;-)

Podsumowując: wystarczy zadzwonić pod numer Dispatcher.Invoke i nie martw się o numer CheckAccess.

+2

Uważam, że warto sprawdzić dostęp do wątku, aby określić, którego użyć. Posiadanie wyraźnej kontroli lub spełnianie określonych wymagań wstępnych w oparciu o CheckAccess ma sens w niektórych przypadkach. Ale wyrabianie tego jest złe, ponieważ byłoby to tylko powielanie wysiłków. Mówiąc szczerze, Dispatcher.cs jest jedną z najbrudniejszych klas .NET, jakie kiedykolwiek widziałem. – erodewald

+0

Jedynym minusem tego jest to, że musisz pamiętać, które metody mogą aktualizować interfejs użytkownika i zawsze używać 'Invoke()' podczas wywoływania, w przeciwieństwie do sprawdzenia/wywołania w metodzie, która gwarantuje, że zawsze działa bez obawy o tym – Basic

+0

Dan Nie jestem pewien, czy masz rację, kiedy mówisz "... jeśli jesteś już na właściwej stronie, to po prostu wywoła twój kod i użyje CheckAccess, aby poradzić sobie z tym zachowaniem." Jeśli spojrzysz na źródło klasy Dispatchera, wydaje się, że wywołuje ona tylko CheckAccess, jeśli DispatcherPriority jest Send. IMO, dobrym pomysłem jest stworzenie klasy opakowania dla ciebie Dispatcher, która jest przydatna do testowania jednostkowego, ale możesz bardzo łatwo dodać CheckAccess dla każdego wywołania Invoke. Wywołanie Dispatchera. Wywołanie wątku głównego spowodowało pewne problemy w przeszłości. – Zoman

0

Dodałbym: jeśli chcesz mimick się "If invokeRequired then ..."
powiedziałbym: nie należy używać "if Dispatcher.CheckAccess" Zamiast używać:

If Me.Dispatcher.Thread Is System.Threading.Thread.CurrentThread Then 
    Label1.Content = value 
Else 
    Me.Dispatcher.BeginInvoke(New Action(Of String)(AddressOf displaymessage), value) 
    Return 
End If 


Kwestia miałem było to, że CheckAccess było zawsze prawdziwe, nawet po zaczynają powoływać ...

Nevermind poniższy kod działa również dobrze:

If Me.Dispatcher.CheckAccess Then 
    Label1.Content = value 
    Else 
    Me.Dispatcher.BeginInvoke(New Action(Of String)(AddressOf displaymessage), value) 
    Return 
End If 
Powiązane problemy