SourceChord

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

WPF/UWP用にBootstrap風Gridレイアウトを行うライブラリを作ってみた~ResponsiveGrid~

超定番cssフレームワークBootstrapのグリッドシステムのようなレイアウトをXAML環境で行うためのライブラリを作ってみました。
f:id:minami_SC:20160702010414g:plain

WPF/UWPともに、Nugetから以下のパッケージをインストールすることで使えます。
NuGet Gallery | ResponsiveGrid 0.3.1
(WPF/UWPともに共通のパッケージとなっています。)

NugetのGUIResponsiveGridで検索すれば出てきます。
f:id:minami_SC:20160702010503p:plain
Nugetのパッケージマネージャ コンソールから、以下のコマンドでもインストールできます。

Install-Package ResponsiveGrid

最初はWPF向けに作り始めたけど、こういうレスポンシブなレイアウトは、デスクトップとモバイルを共通で開発できるUWPのような環境の方が需要ありそうなんで、WPFとUWP両対応なライブラリにしてみました。

使い方

準備

WPF/UWPでXAMLで使用する名前空間の設定方法が若干異なります。
とりあえず、以下のようなxmlnsの設定をすれば準備OK。

WPF

xmlns:rg="clr-namespace:SourceChord.ResponsiveGrid;assembly=ResponsiveGrid.Wpf"

UWP用

xmlns:rg="using:SourceChord.ResponsiveGrid"

レイアウトしてみる

とりあえず、Webデザインでよくありそうな、ヘッダー/フッターと、ナビゲーション領域、コンテンツ領域からなるレイアウトをしてみます。

XAMLでこんな風にレイアウトすると、、

<Window x:Class="ResponsiveGridSample.Wpf.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:ResponsiveGridSample.Wpf"
        xmlns:rg="clr-namespace:SourceChord.ResponsiveGrid;assembly=ResponsiveGrid.Wpf"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.Resources>
            <Style TargetType="{x:Type Border}">
                <Setter Property="BorderBrush" Value="Black" />
                <Setter Property="BorderThickness" Value="1.5" />
                <Setter Property="Background" Value="LightGray" />
                <Setter Property="CornerRadius" Value="5" />
                <Setter Property="Margin" Value="1" />
                <Setter Property="Height" Value="60" />
            </Style>
        </Grid.Resources>
        <rg:ResponsiveGrid Margin="10" BreakPoints="345, 567, 789">
            <Border>
                <TextBlock Text="[Header]"/>
            </Border>
            <Border Height="80" rg:ResponsiveGrid.SM="3" >
                <TextBlock Text="[Navigation]&#xa;-Top&#xa;-Menu1&#xa;-Menu2"/>
            </Border>
            <Border Height="80" rg:ResponsiveGrid.SM="9">
                <TextBlock Text="[Content]"/>
            </Border>
            <Border>
                <TextBlock Text="[Footer]"/>
            </Border>
        </rg:ResponsiveGrid>
    </Grid>
</Window>

ある程度以上のウィンドウ幅がある場合はこんな感じ。
f:id:minami_SC:20160702011249p:plain

ウィンドウの幅を縮めていくと、こんな風に表示が切り替わります。
f:id:minami_SC:20160702011302p:plain

プロパティ

プロパティ名 Type 内容
MaxDivision int 1行当たりのカラム分割数
BreakPoints BreakPoints class XS, SM, MD, LGのレイアウト切替を行うブレークポイントの設定
ShowGridLines int カラム分割位置のガイド表示設定
GridコントロールのShowGridLinesと似た感じ。
MaxDivision

このプロパティで、1行のカラム数を設定できます。

<rg:ResponsiveGrid MaxDivision="24">
BreakPoints

こんな風に、XS, SM, MD, LGのレイアウト変更を行う閾値のサイズを設定できます。

        <rg:ResponsiveGrid>
            <rg:ResponsiveGrid.BreakPoints>
                <rg:BreakPoints XS_SM="345" SM_MD="567" MD_LG="789"/>
            </rg:ResponsiveGrid.BreakPoints>

WPFでは、こんな風に簡単に設定することもできます。

<rg:ResponsiveGrid BreakPoints="345, 567, 789">

(UWPではTypeConverterを自作できないんで、こういうことができません。。。)

ShowGridLines

このプロパティをTrueにすると、Gridコントロールなどと同じようにグリッド位置のガイドライン表示を行います。
ResponsiveGridでは、縦方向のカラム分割位置のみ点線表示を行います。

        <rg:ResponsiveGrid ShowGridLines="True">
            <Border rg:ResponsiveGrid.XS="4" />
            <Border rg:ResponsiveGrid.XS="4" />
        </rg:ResponsiveGrid>

f:id:minami_SC:20160702010525p:plain

添付プロパティ

最初のサンプルで使用した、XS, SMなどのプロパティ以外にも、以下のようなプロパティを用意しています。
Bootstrap使ったことある人なら、なんとなく感覚で使えるのではないでしょうか。

プロパティ名 Type 内容
XS
SM
MD
LG
int XS, SM, MD, LGのそれぞれのカラム数
XS_Offset
SM_Offset
MD_Offset
LG_Offset
int オフセット指定。ここで指定した数だけ、自身より前に余白を作ります。
XS_Push
SM_Push
MD_Push
LG_Push
int ここで指定したカラム数分だけ、本来の位置より右側に移動します。
XS_Pull
SM_Pull
MD_Pull
LG_Pull
int ここで指定したカラム数分だけ、本来の位置より左側に移動します。

工夫した点など

配布形態

WPFとUWPに両対応するため、共有プロジェクトを作ってResponsiveGridクラスの実装コードを共有しています。
プロジェクト構成としてこんな感じ。
f:id:minami_SC:20160702010534p:plain

ResponsiveGrid.Sharedが共有プロジェクトで、コードの大部分はこの中でifdefで処理を分けながら書いてます。
で、ResponsiveGrid.WpfとResponsiveGrid.Uwpが、それぞれWPF用/UWP用のクラスライブラリプロジェクトで、ResponsiveGrid.Sharedの共有プロジェクトを参照しています。

WPFとUWPでは、XAMLの仕様で違う点が色々あったりしますが、
今回はPanel派生クラスをC#コードで書くだけだったので、名前空間の設定やプロパティ定義などを部分的にifdefで切り替えることで対応できました。

TODO

余力のある時に↓みたいなことをしようと思ってます。

  • もうちょっとサンプルコード類を充実させたい
  • Visibility関係のプロパティ類を作成(MDの時だけ表示/非表示みたいな設定とか)