LoginSignup
1
1

More than 3 years have passed since last update.

【C#/WPF】WriteableBitmapで点を打って、テレビの放送終了後の砂嵐をつくる(Taskで処理)

Posted at

タイマーでやる場合

こちらを参照。

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で、重い処理の部分を別スレッドで実施すればよい。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1