2018-8-10-wpf-DoEvents-



2018 8 10 Wpf Doevents



題名 著者 日付 CreateTime カテゴリ
wpf DoEvents lindexi 2018-08-10 19:16:51 +0800 2018-2-13 17:23:3 +0800 WPFdoeventsパフォーマンスの最適化

カードのUIコード実行期間、およびUI応答の作成方法。依存関係プロパティを必要とするタグがある場合、コードはUIスレッドで実行する必要がありますが、その場合、UI、UIの応答性がカード化されるため、DoEvents UI応答を作成する必要があります。最初に知っておく必要がありますDoEvents一部のWinFormでは、WPFはこの関数に含まれていませんが、それ自体を記述できます。

例は、誰もが最初に行うことを知らせますDoEventsミルの役割は非常に単純なままでした。コードを見てください



PushFrameImpl

次に、[OK]をクリックします。表示されます。インターフェースに応答するまで、しばらく待つ必要があります。



DoEventsを追加すると、次の図で効果を確認できます。

使用法

いくつかの変更を加えるために粉砕プログラムにとどまります、コードを見てください



OnLoaded

したがって、ループ内のコードを追加するだけで済みます。次の2つのメソッドをコピーして、必要に応じて呼び出しが必要な場合にUI応答が必要になるようにすることができます。このメソッドの使用は、非常に簡単です。

次の場所での使用をお勧めします。

  • バックグラウンド操作には時間がかかり、完全にロードされていないため、通常どおり使用できます
  • パフォーマンスを最適化する方法はありません
  • 時間パフォーマンスは一時的なプログラムとして最適化されていません
  • DoEventsプロポーザルはメインスレッドで使用する必要があります

原理

下部を見てくださいDispatcher.Invoke次のコードは削除されています

UIは再描画メッセージにつながります:0xC25Aと0xC262がこのメッセージを送信するので、UI応答を許可できます

既存のピット

これがPushFrameピットピットです。彼の原則については、を参照してください。 https://walterlv.github.io/post/dotnet/2017/09/26/dispatcher-push-frame.html

[OK]ボタンをクリックすると、もう一度[OK]ボタンをクリックすると、ロット番号が繰り返し表示されます。この方法を使用する場合は、[OK]ボタンを無効にする必要があり、ユーザーが誤って複数回クリックします。

ウィンドウをドラッグする方法を使用すると、ウィンドウがスタックする可能性があります。

再現する手順:

上記のコードを変更して、グラインドを維持し、プラスDoEventsを使用します。これは、await Task.Delay(2000)またはFoo(10)を使用し、ウィンドウをドラッグして実行すると、ウィンドウがスタックします。

Invoke

ただし、Alt + Tabを使用して他のウィンドウに移動し、戻ってみると、通常のウィンドウが表示されます。

実際、ウィンドウサイズを変更しようとすると、ウィンドウがスタックします。を参照してください。 ユーザーがウィンドウのサイズ変更またはドラッグ中にDispatcher.InvokeまたはDispatcher.PushFrame、あるいはその両方を使用すると、WPFアプリケーションが断続的にハングする

OnLoadの他のピット

これらのOnLoadピットだけでなく、多くの場合、私は条件を知らないと言わなければなりません。

お願いしますDoEvents置き換えDispatcher.Invokeソフトウェアを起動してウィンドウをドラッグしようとすると、ウィンドウの内容が表示されていないことがわかりますが、できる場合はマウスを離してください画面表示を参照してください。

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

次に、Background置換Dispatcher.Invoke同じ結果で、ウィンドウのドラッグを開始します。ウィンドウにはコンテンツがありません。

DispatcherTimerウィンドウの使用がフリーズして表示される

次のコードは、内部に保持される時間を作成するために使用されますSystem.Windows.Threading.Dispatcher.Yield

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

次に、上記と同じように、ウィンドウをドラッグするとフリーズしたように見えます。

上記のコードを実際に操作するとフリーズが解除されますが、フリーズする前に2回、10回試しました。

推奨される方法

Wrは実際に開発者にこのように書くことを許可することを拒否していませんか?実際、garbage wrはこれを実行しましたが、開発者には通知しませんでした。地上に留まろうとする代わりに、次のコードを使用してください。

async

キーはDispatcher.Yield、このコードはメインスレッドに挿入されます

<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) } } }
優先順位があるため、UIに他の入力を処理させることができます

ただし、直接使用

 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 }
コードが長すぎるので、比較的簡単に使用できるのではないでしょうか。実際、まだそこにあります。コードを見てください。

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

実際に

 private void OnLoaded(object sender, RoutedEventArgs e) { Foo(10) Dispatcher.Invoke(() => { }, DispatcherPriority.Background) }
この実装方法と
 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) }
それも異なります。彼は非同期を使用しており、科学技術を他にどのように言うかわかりません。

最後の方法は、実行のメイン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) } }
そして直接使用
 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() } }
UI応答を循環させることができます。 UIはループに陥ることはありません。

最後の方法は、ピットを解決でき、使いやすいため、最後の方法をお勧めします

実際、どの方法でインターフェースを使用しても、必ずしも上記に対応するとは限りませんが、ページにアニメーションのサイクルがある場合は、実際にいくつかのカードでアニメーションを見ることができ、地下滞在を書くことができます。画面の上部に次のコードを追加します。アニメーションを停止しないでください。

 <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>

次に、ボタンをクリックすると、いくつかのカードのアニメーションが表示されます。ウィンドウをクリックしてドラッグすると、アニメーションが正しく表示されます。