wpfと非同期

20
WPF とととと @yone64

Upload: yone64

Post on 30-Jun-2015

2.760 views

Category:

Technology


8 download

TRANSCRIPT

Page 1: Wpfと非同期

WPFと非同期@yone64

Page 2: Wpfと非同期

大前提

Page 3: Wpfと非同期

Control に対し、非同期にプロパティーへのアクセスやオブジェクトの生成を行うと例外が発生する

鉄の掟

Page 4: Wpfと非同期

同期コンテキストで非同期実行する

Page 5: Wpfと非同期

TaskScheduler で、同期コンテキストを指定する。

UIスレッドで実行するために

var t = Task.Factory.StartNew(() =>{ var s = textBox1.Text;},CancellationToken.None,TaskCreationOptions.None,TaskScheduler.FromCurrentSynchronizationContext());

Page 6: Wpfと非同期

Dispatcher を使い実行する。◦ Invoke, BeginInvoke, InvokeAsync など

UIスレッドで実行するために

var t = Task.Run(() =>{ textBox1.Dispatcher.Invoke(() => { var s = textBox1.Text; });});

Page 7: Wpfと非同期

優先度付キュー◦ 優先度が高いものから実行されていく

Dispatcherと優先度

DispatcherPriority◦ Send◦ Normal◦ DataBind◦ Render◦ Loaded◦ Input◦ Background◦ ContextIdle◦ ApplicationIdle◦ SystemIdle◦ Inactive◦ Invalid

Send

Normal

DataBind

Render

① ②

Page 8: Wpfと非同期

頭の体操的なものvar dispatcher = Application.Current.Dispatcher;

dispatcher.BeginInvoke(new Action(() => Console.WriteLine("No1")), DispatcherPriority.Normal);

Console.WriteLine("No2");

dispatcher.BeginInvoke(new Action(() => Console.WriteLine("No3")), DispatcherPriority.Render);

dispatcher.BeginInvoke(new Action(() => Console.WriteLine("No4")), DispatcherPriority.Send);

dispatcher.Invoke(new Action(() => Console.WriteLine("No5")), DispatcherPriority.DataBind);

Console.WriteLine("No6");

Page 9: Wpfと非同期

非同期処理とはいえ、 UI スレッドで処理を行うので、描画は固まります。

バックグランドスレッドでできることは、極力バックグラウンドスレッドでやりましょう。

注意

Page 10: Wpfと非同期

バックグラウンドスレッドでの処理待ち後に、実行するために。

Framework の処理を先に実行させるために。

なぜに非同期

Page 11: Wpfと非同期

同期コンテキスト以外でもできること

Page 12: Wpfと非同期

突然ですが、WPFの主要クラス

DependencyObject

DispatcherObject

Freezable Visual

UIElement ContainerVisual

FrameworkElement

Control

Page 13: Wpfと非同期

プロパティーへのアクセス◦ Freezable のサブクラスは、 Freeze することで別ス

レッドからもアクセス可能になる

オブジェクトの生成◦ 生成ができないのは、 FrameworkElement のサブクラ

ス◦ FrameworkElement のサブクラスでも、 Thread を

STA にすれば生成可能

鉄の掟の抜穴

Page 14: Wpfと非同期

BitmapImage や Brush をバックグラウンドで作成し、利用する。

利用例①

Task.Run(() =>{ var sr = new MemoryStream(new WebClient().DownloadData(new Uri("http://xx/img/1.jpg"))); var bi = new BitmapImage(); bi.BeginInit(); bi.CacheOption = BitmapCacheOption.OnLoad; bi.StreamSource = sr; bi.EndInit();

bi.Freeze(); Application.Current.Dispatcher.Invoke(() => { image.Source = bi; });});

Page 15: Wpfと非同期

メッセージプールを複数作成する。

利用例②

var thread = new Thread(() =>{ var dispacherFrame = new DispatcherFrame(true);

var w = new Window {Width = 800, Height = 600}; var p = new WrapPanel {Orientation = Orientation.Horizontal}; w.Content = p; for (int i = 0; i < 20000; i++) { p.Children.Add(new Button { Height = 30, Width = 120, Content = " ボタン " + i, }); } w.Closed += (o, args) => dispacherFrame.Continue = false; w.Show();

Dispatcher.PushFrame(dispacherFrame);});

thread.SetApartmentState(ApartmentState.STA);thread.Start();

Page 16: Wpfと非同期

UI要素を直接触らない場合

Page 17: Wpfと非同期

Bing はそもそも UI スレッドで処理される。◦ Background からさわっても大丈夫

Bindingと非同期

<TextBox Text="{Binding Text}" Height="23" Width="120" />

Task.Run(() =>{ // エラーにならない _vm.Text = DateTime.Now.ToString();});

Page 18: Wpfと非同期

Binding 経由でも Collection 経由の場合は、非同期アクセスすると例外が発生する

.Net4.5 の場合◦ BindingOperations.EnableCollectionSynchronizatio

n

Collectionの Binding

BindingOperations .EnableCollectionSynchronization(Items, new object());

Page 19: Wpfと非同期

非同期といえば、 Rx だよねって貴方に

「 ReactiveProperty で流れるような WPF 開発を!」

by xin9le

ReactiveProperty

Page 20: Wpfと非同期

メッセージループをアプリケーション内で複数作ってみる - 亀岡的プログラマ日記 ◦ http://

posaune.hatenablog.com/entry/2013/05/21/010735

ReactiveProperty◦ http://reactiveproperty.codeplex.com/

参考