タイマーでやる場合
こちらを参照。
Taskで処理を行うパターン
上の例では、UIとバインドしているプロパティへのアクセス'(MyWBitmap.WritePixels()の部分)'はUIスレッドでしか実施できないため、別スレッドで実施されるTaskを使用せず、タイマで処理をしていたが、
Taskを使った場合でも、UI周りの処理の時だけUIスレッドで処理してもらうということができる。
下記が、そのサンプル。
Dispatcherを使用し、UIスレッドに処理を渡している。
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
namespace WpfApp1
{
class ViewModel : BindingBase
{
public WriteableBitmap MyWBitmap { get; set; } = new WriteableBitmap(1280, 720, 96, 96, PixelFormats.Pbgra32, null);
Dispatcher MainViewDispatcher = null;
public ViewModel(Dispatcher dispatcher)
{
MainViewDispatcher = dispatcher;
Task.Run(() =>
{
while (true)
{
int width = (int)1280;
int height = (int)720;
// 計算用のバイト列の準備
int pixelsSize = (int)(width * height * 4);
byte[] pixels = new byte[pixelsSize];
Random rnd = new System.Random(); // インスタンスを生成
int rndMax = 256; // 0~256の乱数を取得
// バイト列に色情報を入れる
for (int i = 0; i < width * height; i++)
{
pixels[4 * i] = (byte)rnd.Next(rndMax); // blue;
pixels[4 * i + 1] = (byte)rnd.Next(rndMax); // green;
pixels[4 * i + 2] = (byte)rnd.Next(rndMax); // red;
pixels[4 * i + 3] = (byte)255; // alpha
}
// バイト列をBitmapImageに変換する
int stride = width * 4;
// TaskはUIスレッドと別のスレッドのため、ビットマップにバインドしたプロパティの操作はUIスレッドでやってもらう
// そのために、Dispatcherを使う
MainViewDispatcher.BeginInvoke(new Action(() =>
{
MyWBitmap.WritePixels(new Int32Rect(0, 0, width, height), pixels, stride, 0, 0);
}));
Thread.Sleep(33);
}
});
}
}
}
今回は、砂嵐の画面データをつくる処理がそれほど重い処理ではないので問題ないが、なにか重い処理をするような場合は、タイマーでやっているとUIが固まったように見えてしまうことが考えられる。
その場合、上記のように、TaskとDispatcherで、重い処理の部分を別スレッドで実施すればよい。