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.