[WPF] ハンバーガーメニュー(SplitView)を使う


■概要

SplitViewを使用してハンバーガーメニューを実現する。

■準備

🔗ここ を参考に「2. プロジェクト作成」から「5. テーマ適用」まで実施する。

※「2. プロジェクト作成」でプロジェクト名はHamburgerSample、フレームワークは.NET 5.0にした。
※「4. NuGet」は「ModernWpfUI」だけ入れればOK、「ModernWpf.MessageBox」は今回のサンプルでは使っていない。

■コンテンツ部品 追加

ソリューションエクスプローラーでプロジェクト直下に「追加」-「ユーザーコントロール (WPF)」でUserControl1.xamlを追加する。

TextBlockを1つ追加。

UserControl1.xaml
<UserControl
    x:Class="HamburgerSample.UserControl1"
    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:local="clr-namespace:HamburgerSample"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    d:DesignHeight="450"
    d:DesignWidth="800"
    mc:Ignorable="d">
    <Grid>
        <TextBlock
            x:Name="TxtContent"
            Padding="12"
            FontFamily="UD Digi Kyokasho NK-R"
            FontSize="22"
            TextWrapping="Wrap">
            ニャー、ニャーと試みにやって見たが誰も来ない。そのうち池の上をさらさらと風が渡って日が暮れかかる。腹が非常に減って来た。泣きたくても声が出ない。仕方がない、何でもよいから食物のある所まであるこうと決心をしてそろりそろりと池を左りに廻り始めた。どうも非常に苦しい。そこを我慢して無理やりに這って行くとようやくの事で何となく人間臭い所へ出た。ここへ這入ったら、どうにかなると思って竹垣の崩れた穴から、とある邸内にもぐり込んだ。縁は不思議なもので、もしこの竹垣が破れていなかったなら、吾輩はついに路傍に餓死したかも知れんのである。一樹の蔭とはよく云ったものだ。この垣根の穴は今日に至るまで吾輩が隣家の三毛を訪問する時の通路になっている。さて邸へは忍び込んだもののこれから先どうして善いか分らない。
        </TextBlock>
    </Grid>
</UserControl>

■メイン画面作成

ResizeMode="CanResizeWithGrip"追加。
Gridを2行に分割、1行目はハンバーガーボタン。

MainWindow.xaml
<Window
    x:Class="HamburgerSample.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:local="clr-namespace:HamburgerSample"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:ui="http://schemas.modernwpf.com/2019"
    Title="MainWindow"
    Width="800"
    Height="450"
    ui:WindowHelper.UseModernWindowStyle="True"
    ResizeMode="CanResizeWithGrip"
    mc:Ignorable="d">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition />
        </Grid.RowDefinitions>

        <StackPanel Orientation="Horizontal">
            <!--  ハンバーガー ボタン  -->
            <ToggleButton x:Name="HamburgerButton" Click="HamburgerButton_Click">
                <ui:SymbolIcon Symbol="GlobalNavigationButton" />
            </ToggleButton>
            <!--  タイトルテキスト  -->
            <TextBlock
                Margin="6,0"
                VerticalAlignment="Center"
                FontSize="18"
                Text="タイトル" />
        </StackPanel>

        <!--  ハンバーガー メニュー  -->
        <ui:SplitView
            x:Name="Menu"
            Grid.Row="1"
            DisplayMode="Overlay"
            OpenPaneLength="200"
            PaneBackground="{DynamicResource SystemControlPageBackgroundChromeMediumLowBrush}"
            PaneClosed="Menu_PaneClosed">
            <ui:SplitView.Pane>
                <ui:SimpleStackPanel Margin="6" Spacing="6">
                    <ui:SimpleStackPanel.Resources>
                        <!--  ボタン(メニュー項目)のスタイル  -->
                        <Style BasedOn="{StaticResource DefaultButtonStyle}" TargetType="Button">
                            <Setter Property="HorizontalAlignment" Value="Stretch" />
                            <Setter Property="HorizontalContentAlignment" Value="Left" />
                            <EventSetter Event="Click" Handler="FontSizeButton_Click" />
                        </Style>
                    </ui:SimpleStackPanel.Resources>

                    <Button Tag="10">
                        <StackPanel Orientation="Horizontal">
                            <ui:SymbolIcon Symbol="Font" />
                            <TextBlock Text="文字サイズ - 小" />
                        </StackPanel>
                    </Button>
                    <Button Tag="22">
                        <StackPanel Orientation="Horizontal">
                            <ui:SymbolIcon Symbol="Font" />
                            <TextBlock Text="文字サイズ - 中" />
                        </StackPanel>
                    </Button>
                    <Button Tag="36">
                        <StackPanel Orientation="Horizontal">
                            <ui:SymbolIcon Symbol="Font" />
                            <TextBlock Text="文字サイズ - 大" />
                        </StackPanel>
                    </Button>
                </ui:SimpleStackPanel>
            </ui:SplitView.Pane>

            <!--  メインコンテンツ  -->
            <ui:SplitView.Content>
                <ScrollViewer Margin="0,0,0,12">
                    <local:UserControl1 x:Name="MainContent" />
                </ScrollViewer>
            </ui:SplitView.Content>
        </ui:SplitView>
    </Grid>
</Window>

■メイン画面ロジック作成

MainWindow.xaml.cs
using System.Windows;
using System.Windows.Controls.Primitives;
using ui = ModernWpf.Controls;

namespace HamburgerSample
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        /// <summary>
        /// メニューが閉じたとき
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        /// <remarks>
        /// ハンバーガーボタンがOFFにされたりメインコンテンツ部分を触ったとき
        /// </remarks>
        private void Menu_PaneClosed(ui.SplitView sender, object args)
        {
            HamburgerButton.IsChecked = false;
        }

        /// <summary>
        /// ハンバーガーボタンクリック
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void HamburgerButton_Click(object sender, RoutedEventArgs e)
        {
            // ハンバーガーボタンがONの状態ならメニューを開く
            Menu.IsPaneOpen = (sender as ToggleButton)?.IsChecked == true;
        }

        /// <summary>
        /// 文字サイズ変更ボタンクリック
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FontSizeButton_Click(object sender, RoutedEventArgs e)
        {
            // Tagに設定された文字サイズをメインコンテンツのテキストに設定
            MainContent.TxtContent.FontSize =
                double.Parse((sender as FrameworkElement).Tag.ToString());
        }

    }
}

■実行

ハンバーガーボタンをクリック、コンテンツの上にメニューが表示される。

ライトテーマ

■参考