Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować się zalogować lub zmienić katalog.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Użytkownicy oczekują, że aplikacja będzie reagować podczas wykonywania obliczeń, niezależnie od typu maszyny. Oznacza to różne rzeczy dla różnych aplikacji. Dla niektórych przekłada się to na zapewnienie bardziej realistycznej fizyki, szybsze ładowanie danych z dysku lub internetu, szybkie prezentowanie złożonych scen i nawigowanie między stronami, szybkie znajdowanie kierunków lub szybkie przetwarzanie danych. Niezależnie od typu obliczeń użytkownicy chcą, aby aplikacja działała na ich danych wejściowych i eliminuje wystąpienia, w których wydaje się nie odpowiadać, gdy "myśli".
Aplikacja jest sterowana zdarzeniami, co oznacza, że kod wykonuje pracę w odpowiedzi na zdarzenie, a następnie pozostaje w stanie bezczynności do następnego. Kod platformy dla interfejsu użytkownika (układ, dane wejściowe, wywoływanie zdarzeń itp.) oraz kod aplikacji dla interfejsu użytkownika są wykonywane w tym samym wątku interfejsu użytkownika. Tylko jedna instrukcja może być wykonywana w tym wątku w danym momencie, więc jeśli przetwarzanie zdarzenia przez kod aplikacji trwa zbyt długo, framework nie może uruchomić układu ani zgłosić nowych zdarzeń reprezentujących interakcję użytkownika. Responsywność aplikacji jest związana z dostępnością wątku interfejsu użytkownika do przetwarzania zadań.
Musisz użyć wątku interfejsu użytkownika, aby wprowadzić prawie wszystkie zmiany w wątku interfejsu użytkownika, w tym tworzenie typów interfejsu użytkownika i uzyskiwanie dostępu do ich członków. Nie można zaktualizować interfejsu użytkownika z wątku w tle, ale możesz wysłać do niego komunikat za pomocą CoreDispatcher.RunAsync, aby kod został tam uruchomiony.
Uwaga Jednym wyjątkiem jest to, że istnieje oddzielny wątek renderowania, który może stosować zmiany interfejsu użytkownika, które nie wpływają na sposób przetwarzania danych wejściowych ani na podstawowy układ. Na przykład wiele animacji i przejść, które nie mają wpływu na układ, może być uruchamianych w tym wątku renderowania.
Opóźnienie tworzenia wystąpienia elementu
Niektóre z najwolniejszych etapów w aplikacji mogą obejmować uruchamianie i przełączanie widoków. Nie rób więcej pracy niż jest to konieczne, aby wyświetlić interfejs użytkownika, który użytkownik widzi początkowo. Na przykład nie twórz interfejsu użytkownika z progresywnym odkrywaniem ani zawartości wyskakujących okienek.
- Użyj atrybutu x:Load lub x:DeferLoadStrategy, aby opóźnić inicjalizację elementów.
- Programowe wstawianie elementów do drzewa na żądanie.
CoreDispatcher.RunIdleAsync kolejki działają, aby wątek interfejsu użytkownika był przetwarzany, gdy nie jest zajęty.
Używanie asynchronicznych interfejsów API
Aby ułatwić reagowanie aplikacji, platforma udostępnia asynchroniczne wersje wielu interfejsów API. Asynchroniczny interfejs API zapewnia, że aktywny wątek wykonywania nigdy nie jest blokowany na dłużej. Gdy wywołujesz API z wątku interfejsu użytkownika, użyj wersji asynchronicznej, jeśli jest dostępna. Aby uzyskać więcej informacji na temat programowania za pomocą asynchronicznych wzorców, zobacz Programowanie asynchroniczne lub Wywoływanie asynchronicznych interfejsów API w języku C# lub Visual Basic.
Przekazywanie zadań na wątki działające w tle
Zapisywanie procedur obsługi zdarzeń w celu szybkiego powrotu. W przypadkach, gdy należy wykonać nieztrivialną ilość pracy, zaplanuj ją na wątku w tle i zakończ.
Możesz zaplanować pracę asynchronicznie przy użyciu operatora await w języku C#, operatora Await w Visual Basic lub delegatów w języku C++. To nie gwarantuje jednak, że zadanie, które zaplanujesz, zostanie uruchomione w tle. Wiele interfejsów API platformy uniwersalnej systemu Windows (UWP) zleca wykonywanie zadań w wątku w tle, ale jeśli wywołasz kod aplikacji przy użyciu tylko await lub delegata, uruchomisz ten delegat lub metodę w wątku interfejsu użytkownika. Musisz jawnie powiedzieć, kiedy chcesz uruchomić kod aplikacji w wątku w tle. W językach C# i Visual Basic można to zrobić, przekazując kod do task.Run.
Pamiętaj, że dostęp do elementów interfejsu użytkownika można uzyskać tylko z wątku interfejsu użytkownika. Użyj wątku interfejsu użytkownika, aby uzyskać dostęp do elementów interfejsu użytkownika przed uruchomieniem pracy w tle i/lub użyj CoreDispatcher.RunAsync lub CoreDispatcher.RunIdleAsync w wątku w tle.
Przykładem pracy, którą można wykonać w wątku w tle, jest obliczanie sztucznej inteligencji komputera w grze. Wykonanie kodu, który oblicza następny ruch komputera, może zająć dużo czasu.
public class AsyncExample
{
private async void NextMove_Click(object sender, RoutedEventArgs e)
{
// The await causes the handler to return immediately.
await System.Threading.Tasks.Task.Run(() => ComputeNextMove());
// Now update the UI with the results.
// ...
}
private async System.Threading.Tasks.Task ComputeNextMove()
{
// Perform background work here.
// Don't directly access UI elements from this method.
}
}
Public Class AsyncExample ' ... Private Async Sub NextMove_Click(ByVal sender As Object, ByVal e As RoutedEventArgs) Await Task.Run(Function() ComputeNextMove()) ' update the UI with results End Sub Private Async Function ComputeNextMove() As Task ' ... End Function ' ... End Class
W tym przykładzie program obsługi NextMove_Click kontynuuje działanie w momencie await, aby utrzymać responsywność wątku interfejsu użytkownika. Jednak wykonanie jest wznowione w tej obsłudze po zakończeniu ComputeNextMove (co odbywa się w wątku w tle). Pozostały kod w procedurze obsługi aktualizuje interfejs użytkownika na podstawie wyników.
Uwaga istnieje również interfejs APIThreadPool i interfejs APIThreadPoolTimer dla platformy UWP, który może być używany w podobnych scenariuszach. Aby uzyskać więcej informacji, zobacz Programowanie wątkowe i asynchroniczne.