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