[C# WPF] ScrollViewer内にWriteableBitmapで描画してみる
前回に引き続き、もうちょっとWriteableBitmapを使ってみます。
今回はScrollViewerで表示されている部分にだけ、WriteableBitmapで描画を行います。
環境
- Visual Studio 2019
- .NET Framework 4.7.2
ScrollViewerの表示領域にだけ描画してみる
何も考えずにImageを置き換えるとこんな感じになります。
・MainWindow.xaml
<Window x:Class="Sample_WriteableBitmap.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:Sample_WriteableBitmap" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <ScrollViewer x:Name="xScrollViewer" HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible" ScrollChanged="ScrollViewer_ScrollChanged"> <!-- Windowの3倍くらいのCanvasを入れておく --> <Canvas x:Name="xCanvas" Height="1800" Width="2400"> <Image x:Name="xImage"/> </Canvas> </ScrollViewer> </Window>
・MainWindow.xaml.cs
using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Media.Imaging; namespace Sample_WriteableBitmap { public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); DrawImage(); } private void ScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e) { DrawImage(); } private void DrawImage() { // WritableBitmapを生成する // ScrollViewerの表示領域ではなくCanvas自体のサイズを指定します var canvasWidth = (int)xCanvas.Width; var canvasHeight = (int)xCanvas.Height; var bitmap = new WriteableBitmap(canvasWidth, canvasHeight, 96, 96, PixelFormats.Pbgra32, null); // 描画データを格納するバイト列を生成する // バイト列のサイズはScrollViewerでの表示領域の分だけ作ります var windowWidth = (int)Width; var windowHeight = (int)Height; var size = windowWidth * windowHeight * 4; var pixels = new byte[size]; // バイト列に描画データを格納する for (int i = 0; i < size; i += 4) { pixels[i] = 255; // Blue pixels[i + 1] = 0; // Green pixels[i + 2] = 0; // Red pixels[i + 3] = 255; // Alpha } // スクロール位置に合わせてオフセット距離を算出します // オフセット後の描画でCanvas領域をはみ出すとクラッシュするのでリミットを掛けます var destinationX = (int)xScrollViewer.HorizontalOffset; destinationX = (destinationX < 0) ? 0 : (canvasWidth - windowWidth) < destinationX ? (canvasWidth - windowWidth) : destinationX; var destinationY = (int)xScrollViewer.VerticalOffset; destinationY = (destinationY < 0) ? 0 : (canvasHeight - windowHeight) < destinationY ? (canvasHeight - windowHeight) : destinationY; // バイト列 -> BitmapImage var stride = windowWidth * 4; // 1行あたりのバイト数 bitmap.WritePixels(new Int32Rect(0, 0, windowWidth, windowHeight), pixels, stride, destinationX, destinationY); // 転送 xImage.Source = bitmap; } } }
大したことをやっていないのに描画が遅い気がする。
スクロールバーを掴んで動かしているとチラつくときがあります。
WriteableBitmapは、自前でゼロから何かを描く処理には適していないっぽいですね。
画像を読み込んで編集するときには良さそうです。
おしまい。
ディスカッション
コメント一覧
まだ、コメントがありません