.NETで作る!

.NETに関するあれこれ(C#、VB.NET)

WPF Frameコントロールの見た目を変える

カスタム

f:id:mk3008net:20150201164801p:plain

ちなみにデフォルトだとこれ。

f:id:mk3008net:20150201164755p:plain

経緯

WPFのFrameコントロールは画面遷移のコントロールとしてとても便利ですが、ツールバー(NavigationUIVisibility)の領域が非常に無駄。戻るボタンがちっこい。してなぜかこのコントロールだけグローエフェクトがかかっていてる…となんとなく不満。

モチベーションを上げるため(?)に、カスタマイズしましょう。

Frameコントロール

とりあえず、NavigationUIVisibility=Hiddenとすれば、ださカッコいいツールバーは消えます。

このままだと戻る、進むボタンが使えなくなって不便なので、これをボタンをバインディングしたいわけですが、標準ではできないようです。というわけであんまりやりたくはなかったですが、Frameコントロールを継承して、アクセッサを用意しましょう。

Imports Microsoft.Practices.Prism.Commands

Public Class FrameContainer
    Inherits Frame

    Public Sub New()
        Me.GoBackCommand = New DelegateCommand(AddressOf Me.GoBack, Function() Me.CanGoBack)
        Me.GoForwardCommand = New DelegateCommand(AddressOf Me.GoForward, Function() Me.CanGoForward)

        Me.InitializeCommandProperties()
    End Sub

    ''' <summary>
    ''' 戻るコマンド
    ''' </summary>
    Public Property GoBackCommand As DelegateCommand

    ''' <summary>
    ''' 前へコマンド
    ''' </summary>
    Public Property GoForwardCommand As DelegateCommand

    ''' <summary>
    ''' コマンドプロパティを初期化します
    ''' </summary>
    ''' <remarks></remarks>
    Private Sub InitializeCommandProperties()End Sub
End Class

これでGoBackCommandGoForwardCommandバインディングすればOK。これで一応目的は達成ですが、せっかく(?)なのでもうちょっと凝って、矢印アイコンを付けてみましょう。

アイコン

矢印アイコンはNugetから入手できます。

NuGet Gallery | MahApps.Metro.Resources.Standalone 0.1.0

利用できるアイコンは矢印だけでなく1,000種類以上です。プレビューはこちら(Modern UI Icons)を参照してください。

ちなみに類似パッケージに「MahApps.Metro.Resources(Standaloneでない)」がありますが、こちらはアイコンリソース以外のコントロールも入手できるようですが、今回はアイコンのみ使いたいのでStandalone版を使うこととします。

<ResourceDictionary Source="Resources/Icons.xaml" />でリソースを参照できるようにして、サークル(appbar_base)と、矢印(appbar_arrow_left)を組み合わせて表示させてみましょう。

<Window x:Class="MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:PrismMvvmApplication" 
    Title="MainWindow" Height="350" Width="525"
    DataContext="{Binding MainViewModel, Source={StaticResource Locator}}" WindowStartupLocation="CenterScreen">
    <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Resources/Icons.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>
    <DockPanel>
        <StackPanel Orientation="Horizontal" DockPanel.Dock="Top" Margin="0,0,0,12">
            <Button Command="{Binding ElementName=MainFrame, Path=GoBackCommand}" Height="32">
                <StackPanel Orientation="Horizontal">
                    <Grid>
                        <Rectangle Width="12" Height="12" Fill="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=Foreground}">
                            <Rectangle.OpacityMask>
                                <VisualBrush Stretch="Fill" Visual="{StaticResource appbar_arrow_left}" />
                            </Rectangle.OpacityMask>
                        </Rectangle>
                        <Rectangle Width="24" Height="24" Fill="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=Foreground}">
                            <Rectangle.OpacityMask>
                                <VisualBrush Stretch="Fill" Visual="{StaticResource appbar_base}" />
                            </Rectangle.OpacityMask>
                        </Rectangle>
                    </Grid>
                    <TextBlock Margin="6,0,6,0" VerticalAlignment="Center" Text="Back" />
                </StackPanel>
            </Button>
            <!-- 略 -->
        </StackPanel>        
        <local:FrameContainer NavigationUIVisibility="Hidden" x:Name="MainFrame" Source="{Binding StartupUri}" />
    </DockPanel>
</Window>

ちょっと脱線してしまいましたが、これでナビゲーションボタンを好きにレイアウトできるようになりました。あとはボタンをフラットっぽくしたら完璧ですね。それはまたの機会に…

ダウンロード

一応リンクを張っておきますが、Prismの勉強のために作ったプロジェクトですので、記事の内容以外のコードも多分に含んでいます。ご了承ください。

. .