WPF/UWP:コントロールのエッジをシャープに描画するには?[XAML].NET TIPS

WPFアプリなどではコントロールのエッジがきれいに描画されないことがある。.NET 4で導入されたプロパティを使い、これを修正する方法を紹介する。

» 2016年02月17日 05時00分 公開
[山本康彦BluewaterSoft/Microsoft MVP for Windows Development]
.NET TIPS
Insider.NET

 

「.NET TIPS」のインデックス

連載目次

対象:.NET 4以降


 UIコントロールのエッジがボケて表示されてしまって困ったことはないだろうか? あるいは、表示した画像のピクセルがボケて表示されたことはないだろうか? .NET 4のWPFからは、それを簡単に解決するプロパティが追加された。本稿ではその方法を解説する。

問題

 次の画像が、今回の問題の例だ(4倍に拡大している)。二つの図形を左右に描いているが、右側で問題が発生している。赤い枠線は1ピクセル幅、その内側に1ピクセル空けて緑色の矩形を描画しているのだが、右側ではボケてしまっている。

UIコントロールのエッジがボケてしまう例(WPF) UIコントロールのエッジがボケてしまう例(WPF)
WPFで作成したアプリをWindows 10で実行している。この画像は、4倍に拡大してある。
赤枠と緑の矩形、左右どちらも同じようなXAMLコードを記述しているのだが、右側だけエッジがボケて表示されている。赤枠と緑の矩形の間に1ピクセル幅の空白があるのだが、右側では滲んでしまって分からない。

 この現象は、プログラムの側で指定したピクセルとデバイスの実ピクセルが一致しないときに発生する。プログラムの側で小数点以下の端数が付いた座標を指定しても発生するし、システムが画面解像度によって描画を拡大/縮小する過程でも発生することがある。

 上の例では、次のコードのようにわざと小数点以下の端数が付いた座標を指定している。しかし、意識していなくても、例えばグリッドを「*」指定で3分割したりすれば座標に端数が付いてしまうのである。

<StackPanel Orientation="Horizontal" >
  <Border Width="32" Height="32" Margin="2" 
        HorizontalAlignment="Left" VerticalAlignment="Top"
        BorderThickness="1" BorderBrush="Red">
    <Border Width="28" Height="28" Background="Green" />
  </Border>
  <Border Width="32" Height="32" Margin="2.3"
        HorizontalAlignment="Left" VerticalAlignment="Top"
        BorderThickness="1" BorderBrush="Red">
    <Border Width="28" Height="28" Background="Green" />
  </Border>
</StackPanel>

上の実行例のソースコード(XAML)
要所のみを掲載する。
右側の赤枠には、Marginプロパティに「2.3」という端数を指定している。ここではそれが原因で描画のエッジがボケてしまったのだ。

コントロールのエッジをシャープに描画するには?

 上記の問題を解決するには、UseLayoutRoundingプロパティをtrueに設定すればよい(次のコードと画像)。

 その設定は、トップレベルのGridコントロールで行うとよい。子要素で設定した場合、トップレベルからその子要素までの間で座標計算に端数が出ていると、やはりボケてしまうからだ。

<Window ……省略……
        Title="MainWindow" Height="350" Width="525">
  <Grid x:Name="rootGrid" UseLayoutRounding="True">
    ……省略……

上の問題を解決するソースコード(XAML)
要所のみを掲載する。
UseLayoutRoundingプロパティをtrueに設定するだけで、今回の問題は解決する。

UseLayoutRoundingプロパティをtrueに設定した例(WPF) UseLayoutRoundingプロパティをtrueに設定した例(WPF)
WPFで作成したアプリをWindows 10で実行している。この画像は、4倍に拡大してある。
赤枠と緑の矩形、左右どちらもシャープに描画された。

 なお、.NET 4以前の場合はUseLayoutRoundingプロパティがないので、代わりにSnapsToDevicePixelsプロパティを利用する。ただし、SnapsToDevicePixelsプロパティはUIコントロールの位置決めを実ピクセルに合わせるだけなので、DrawingContextを使って直接描画する場合や画像の内部などには効果がない。

 また、WindowsストアアプリやUWPアプリで使うWindows Runtimeでは、UseLayoutRoundingプロパティの既定値はtrueに変更されているため、基本的にはこの問題は生じない*1

*1 generic.xamlでUseLayoutRoundingプロパティがfalseに設定されている箇所があるので注意が必要だ。UWPでも、ラジオボタンの円やチェックボックスの四角などがfalseになっている。


まとめ

 描画位置を実ピクセルに合わせるにはUseLayoutRoundingプロパティをtrueに設定する。ただし、このプロパティをサポートしているのは.NET 4からなので注意してほしい。

利用可能バージョン:.NET Framework 4以降
カテゴリ:WPF/XAML 処理対象:コントロール
使用ライブラリ:FrameworkElementクラス(System.Windows名前空間)


「.NET TIPS」のインデックス

.NET TIPS

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。