大した記事ではないですが備忘録代わりに。

WPF には Windows 上で動く手前、そのほとんどが DirectX で描画されている一方で、Win32 時代の遺産を利用できるようにするために、System.Windows.Interop.HwndHost という相互運用機構が用意されています。これを実装するコントロールを利用することで WPF でも ActiveX や Windows Forms のコントロールを利用することができるようになっています。そして Web ページを表示する機能を持つ WebBrowser コントロールも同様に HwndHost の派生クラスです。

HwndHostFrameworkElement の派生クラスでこそありますが、継承しているプロパティの多くが他の WPF コントロールのようには動作しません。透明度や変形といった WPF 特有の機能のほか、スクロール領域や要素の切り取り、重ね合わせといったレイアウトにも対応していません。これはたとえば次のような例で問題が起きます。

WPF でインターネット上にある画像を表示させる場合、その URI を BitmapImage に指定することで表示することができます。

<Image>
    <Image.Source>
        <BitmapImage UriSource="https://chitoku.jp/media/icon.png" />
    </Image.Source>
</Image>
var img = new Image();
img.Source = new BitmapImage(new Uri("https://chitoku.jp/media/icon.png"));
var img = new Image();
var source = new BitmapImage();
source.BeginInit();
source.UriSource = new Uri("https://chitoku.jp/media/icon.png");
source.EndInit();
img.Source = source;

でもこの BitmapImage における読み込み処理は UI スレッドで行われているようです。つまり、画像のダウンロードに時間がかかったり、画像の数が多かったりすると、他の要素の表示速度にも影響を与えることがあるということです。今回は、XAML 側から利用できるバッググラウンド処理の機構を考えてみます。

今回は .NET Framework で動作する UI フレームワーク、WPF 4 のお話です。

WPF では大量のアイテムを表示するために ItemsControl というコントロールが用いられますが、多くのアイテムを描画するには時間がかかる上、パフォーマンスの悪化にもつながります。そこで WPF ではアイテムを高速かつ省メモリで描画するために、UI 仮想化という機能が用意されており、ItemsControl の派生コントロールである ListBox などではこれが既定でオンになっています。やったぜ!

というわけにもいかず……本題はここからです。
ListBox ではアイテムをスクロールするときに、アイテム単位でのスクロールが行われます。アイテム単位でのスクロールでは、ボックスからはみ出てしまった文字を読むことができないほか、アイテムによって高さが違う場合、スクロールしたときに読みにくくなってしまいます。