SourceChord

C#とXAML好きなプログラマの備忘録。最近はWPF系の話題が中心です。

FluentWPF v0.2.0~AcrylicPanel/DropShadowPanelの追加~

先日、↓のFluent Design SystemをWPFで再現するライブラリを作りましたが、ちょこっとバージョンアップしてみました。

sourcechord.hatenablog.com

f:id:minami_SC:20180110081212p:plain

主に以下のような変更を行いました。

  • 新規コントロールの追加
    • AcrylicPanel・・・・・・背景ぼかし処理をするパネル
    • DropShadowPanel・・・影の表示方法に少し手を入れたDropShadowEffect付きパネル
  • バグフィックス
    • AcrylicBrushのバグフィックス
      AcrylicBrush使用時に、LayoutChangedイベントが発生し続けて、CPU負荷が高くなる不具合を修正
    • AcrylicWindowのWin10環境以外への対応
      Win10以外の環境では、AcrylicWindowの背景ぼかし処理を無効化しました。

Acrylicなぼかしウィンドウの作成には、SetWindowCompositionAttributeという非公開API使っているので、以前のOSへの対応はやっぱ仕組み的に難しいですね。。。
ということで、Win10以外のOSでは、AcrylicWindowのぼかし処理を無効化しました。
(Win7ならAeroGrass効果をうまく使えば、それっぽい表示を真似できるかもしれませんが。。)

新規コントロール

  • AcrylicPanel・・・・・・背景ぼかし処理を持ったパネル
  • DropShadowPanel・・・影の表示方法に少し手を入れたDropShadowEffect付きパネル

これらは、○○Panelという名前にしてますが、WPFのPanel派生なレイアウト用コントロールではありません。
命名は少し悩みましたが、UWP Community ToolkitにもDropShadowPanelという名前で似たような内容のコントロールがあるので、こんな名前のコントロールにしました。

AcrylicPanel

f:id:minami_SC:20180110081126p:plain

        <fw:AcrylicPanel Grid.ColumnSpan="2"
                   Width="200" Height="200" HorizontalAlignment="Right"
                         Target="{Binding ElementName=grid}"
            <TextBlock Text="TextBlock" HorizontalAlignment="Center" VerticalAlignment="Center"/>
        </fw:AcrylicPanel>

Targetプロパティで、ぼかし対象の領域を指定します。
Targetで指定した要素をVisualBrushとして利用し、ぼかしエフェクトなどをかけています。
そのため、VisualTree上で親に当たるものをTargetとすると、VisualBrushのレンダリングが無限ループとなり正常に描画されません。親子関係にある要素同士では使わないように注意してください。

DropShadowPanel

f:id:minami_SC:20180110081138p:plain

        <fw:DropShadowPanel Grid.Row="1"
                            ShadowMode="Outer" Margin="50">
            <TextBlock Text="ShadowMode: Outer"
                           HorizontalAlignment="Center" VerticalAlignment="Center"/>
        </fw:DropShadowPanel>

以下のような3つのモードで、DropShadowEffectをかけるコントロールです。

  • ShadowModeプロパティ
    • Content・・・子要素すべてにまとめて影を付けます。
    • Inner・・・・・DropShadowPanelの内側にのみ影を表示するモード。内部に凹んだような表示を簡単に作れます。
    • Outer・・・・DropShadowPanelの外側にのみ影を表示します。パネル背景が半透明な場合などに、コントロール内部に影が表示され、パネル内部の色味がDropShadowに影響されるのを防ぐことができます。

XAMLではDropShadowEffectなどのEffectを利用すると、そのEffectがかかったコントロールと子孫要素は、ベクター形式の描画ではなくなります。またClearTypeなどの効果も効かなくなってしまいます。
f:id:minami_SC:20180110081151p:plain
DropShadowPanelでは、影と子要素を別々に描画しているので、DropShadowをかけつつ内部の子要素は通常どおりの表示ができるようにしています。