2018-8-10-wpf-DoEvents-

2018 8 10 Wpf Doevents



tytuł autor data CreateTime kategorie
wpf DoEvents lindexi 2018-08-10 19:16:51 +0800 2018-02-13 17: 23: 3 +0800 WPF doevents Optymalizacja wydajności

Jeśli okres wykonania kodu interfejsu użytkownika karty, a następnie jak wykonać odpowiedź interfejsu użytkownika. Jeśli istnieją tagi, które wymagają właściwości zależności, kod musiałby zostać wykonany w wątku UI, ale wtedy będzie to karta UI, responsywność UI do wykonania, więc musimy użyć DoEvents Aby uzyskać odpowiedź UI. najpierw musisz wiedzieć, DoEvents W niektórych WinForm WPF nie jest w tej funkcji, ale możesz sam napisać.

Przykład, aby wszyscy wiedzieli, jak zrobić najpierw DoEvents Rola młyna była bardzo prosta, spójrz na kod



PushFrameImpl

Następnie kliknij OK, widzisz, musimy trochę poczekać, zanim będą mogli odpowiedzieć interfejsowi





Jeśli dodasz DoEvents, możesz zobaczyć efekt na poniższym rysunku

stosowanie

Pozostań w programie szlifowania, aby wprowadzić zmiany, zobacz kod



OnLoaded

Więc wystarczy dodać kod w pętli na nim. Możesz skopiować następujące dwie metody, aby odpowiedź interfejsu użytkownika była wymagana, gdy wywołania w razie potrzeby, użycie metody jest bardzo proste.

Zalecany do stosowania w następujących miejscach:

  • Operacja w tle jest czasochłonna, nie jest w pełni załadowana, może być normalnie używana
  • Nie mamy możliwości optymalizacji wydajności
  • Wydajność czasowa nie jest zoptymalizowana jako program tymczasowy
  • Propozycje DoEvents muszą być używane w głównym wątku

zasada

Spójrz na dół Dispatcher.Invoke Poniższy kod został usunięty

Interfejs użytkownika doprowadzi do przerysowania wiadomości: 0xC25A i 0xC262 wyślij tę wiadomość, aby umożliwić odpowiedź interfejsu użytkownika

Istniejący dół

Oto pit pit PushFrame, o jego zasadach, patrz https://walterlv.github.io/post/dotnet/2017/09/26/dispatcher-push-frame.html

Jeśli klikniesz przycisk OK, kliknij ponownie przycisk OK, powtórzy się pojawi się numer partii. Jeśli używasz tej metody, musisz wyłączyć przycisk OK, użytkownik przypadkowo kliknie wiele razy.

W przypadku korzystania z metody przeciągania okna może dojść do zablokowania okna.

Kroki ku reprodukcji:

Zmodyfikuj powyższy kod, aby pozostać grindem, plus DoEvents, które używają await Task.Delay(2000) lub Foo(10) A następnie przeciągnij okno, a następnie okno utknęło

Invoke

Ale potem użyj Alt + Tab do innego okna, a potem wróć, możesz zobaczyć normalne okno

W rzeczywistości próba zmiany rozmiaru okna powoduje również zablokowanie okna, zobacz Aplikacja WPF sporadycznie zawiesza się podczas korzystania z Dispatcher.Invoke i / lub Dispatcher.PushFrame, gdy użytkownik zmienia rozmiar lub przeciąganie okna

Inne doły na OnLoad

Muszę powiedzieć, że nie tylko będą to kopalnie OnLoad, ale także w wielu przypadkach, ale nie znam warunków.

proszę DoEvents Zastąpione Dispatcher.Invoke Niektóre obliczenia, a następnie po uruchomieniu programu i próbie przeciągnięcia okna, możesz zobaczyć, że zawartość okna nie jest wyświetlana, ale puść mysz, kiedy możesz zobaczyć wyświetlacz ekranu.

Dispatcher.Invoke(() => { }, DispatcherPriority.Background)

Następnie Background Zastąpione Dispatcher.Invoke Te same wyniki, zacznij przeciągać okno, okno nie ma zawartości.

Okno Use DispatcherTimer jest zamrożone

Poniższy kod służy do tworzenia czasu przechowywanego w środku System.Windows.Threading.Dispatcher.Yield

Dispatcher.Invoke(() => { }, DispatcherPriority.Background

Następnie przeciągnij okno zamrożone, tak samo jak powyżej.

Rzeczywiste działanie powyższego kodu usunie zamrożenie, ale próbowałem 10 razy, 2 razy przed zamrożeniem, gdy puściłem.

Zalecana metoda

Wr właściwie nie odmawia programistom pozwolenia na pisanie w ten sposób? W rzeczywistości garbage wr zrobił to, ale nie powiedział programistom, użyj poniższego kodu zamiast próbować pozostać nad ziemią

async

Klucz to Dispatcher.Yield, ten kod jest wstawiany w głównym wątku

<Window x:Class='ZuindmMbx.MainWindow' xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' xmlns:d='http://schemas.microsoft.com/expression/blend/2008' xmlns:mc='http://schemas.openxmlformats.org/markup-compatibility/2006' xmlns:local='clr-namespace:ZuindmMbx' mc:Ignorable='d' Title='MainWindow' Height='350' Width='525'> <Grid> <ListView ItemsSource='{Binding KatudefZubpobryk}'> <ListView.ItemTemplate> <DataTemplate> <TextBlock Text='{Binding}'></TextBlock> </DataTemplate> </ListView.ItemTemplate> </ListView> <Button Content='determine' HorizontalAlignment='Left' Margin='424,292,0,0' VerticalAlignment='Top' Width='75' Click='Button_OnClick'/> </Grid> </Window> public partial class MainWindow : Window { public MainWindow() { InitializeComponent() DataContext = this } public ObservableCollection<string> KatudefZubpobryk { get set } = new ObservableCollection<string>() private void Button_OnClick(object sender, RoutedEventArgs e) { for (int i = 0 i < 10 i++) { Foo(10) KatudefZubpobryk.Add(i.ToString()) } } private void Foo(int n) { for (int i = 0 i < n i++) { Foo(n - 1) } } }
Ponieważ priorytet, możesz pozwolić interfejsowi użytkownika obsługiwać inne dane wejściowe

Jednak bezpośrednie użycie

 private void Button_OnClick(object sender, RoutedEventArgs e) { for (int i = 0 i < 10 i++) { Foo(10) KatudefZubpobryk.Add(i.ToString()) DoEvents() } } public static void DoEvents() { DispatcherFrame frame = new DispatcherFrame() Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, new DispatcherOperationCallback(ExitFrame), frame) Dispatcher.PushFrame(frame) } private static Object ExitFrame(Object state) { ((DispatcherFrame) state).Continue = false return null }
Kod jest za długi, czy nie można go używać stosunkowo prosto? W rzeczywistości nadal tam jest, spójrz na kod.

 public MainWindow() { InitializeComponent() DataContext = this Loaded += OnLoaded } private async void OnLoaded(object sender, RoutedEventArgs e) { await Task.Delay(2000) Dispatcher.Invoke(() => { }, DispatcherPriority.Background) }

Właściwie

 private void OnLoaded(object sender, RoutedEventArgs e) { Foo(10) Dispatcher.Invoke(() => { }, DispatcherPriority.Background) }
Ta metoda implementacji i
 public MainWindow() { InitializeComponent() DataContext = this Loaded += OnLoaded DispatcherTimer time = new DispatcherTimer() time.Interval = new TimeSpan(0, 0, 1) time.Tick += Time_Tick time.Start() } private void Time_Tick(object sender, EventArgs e) { Foo(10) Dispatcher.Invoke(() => { }, DispatcherPriority.Background) }
Jest też inna, on używa async i nie wiem, jak inaczej powiedzieć nauka i technologia.

Ostatnią metodą jest dodanie funkcji w głównym wątku wykonawczym UI

 private void Button_OnClick(object sender, RoutedEventArgs e) { for (int i = 0 i < 10 i++) { Foo(10) KatudefZubpobryk.Add(i.ToString()) Dispatcher.Invoke(() => { }, DispatcherPriority.Background) } }
I bezpośrednie użycie
 private async void Button_OnClick(object sender, RoutedEventArgs e) { for (int i = 0 i < 10 i++) { Foo(10) KatudefZubpobryk.Add(i.ToString()) await System.Windows.Threading.Dispatcher.Yield() } }
Możemy pozwolić cyklowi odpowiedzi interfejsu użytkownika. Interfejs użytkownika nie pozwoli utknąć w pętli.

Ostatnia metoda jest zalecana, ponieważ ta metoda może rozwiązać dół i jest łatwa w użyciu

W rzeczywistości, niezależnie od tego, która metoda korzystania z interfejsu nie zawsze będzie odpowiadać na powyższe, jeśli na stronie znajduje się cykl animacji, możesz zobaczyć animację w rzeczywistości niektóre karty, napisz pobyt pod ziemią możesz poznać. Dodaj następujący kod u góry ekranu, nie zatrzymuj animacji.

 <Grid> <Grid.Triggers> <EventTrigger RoutedEvent='Grid.Loaded'> <BeginStoryboard> <Storyboard RepeatBehavior='Forever'> <DoubleAnimation Storyboard.TargetName='T' Storyboard.TargetProperty='Angle' From='0' To='360' Duration='0:0:1'></DoubleAnimation> </Storyboard> </BeginStoryboard> </EventTrigger> </Grid.Triggers> <Grid x:Name='G' Background='#565656' Width='200' Height='200' HorizontalAlignment='Center' VerticalAlignment='Center'> <Grid.RenderTransform> <RotateTransform x:Name='T' CenterX='100' CenterY='100' Angle='0'></RotateTransform> </Grid.RenderTransform> </Grid> </Grid>

Następnie kliknij przycisk, możesz zobaczyć animację niektórych kart, możesz kliknąć i przeciągnąć okno, aby wyświetlić animację poprawnie.