11.OpenCVで画像処理アプリを作ろう(HambergerMenu)

こんにちは、ゆたんぽです。

今回は前回紹介したHambergerMenuを実装していこうと思います。

記事を書いている途中、長くなったと感じたので2編構成にしていきます。


HambergerMenuとは

まずはどんな画面か見た方が早いので下にGIFを載せます。

HamburgerMenu とはスマホのアプリやWeb サイトのメニュー等に使用される場合が多いものです。


上の図で示した、左上の 3 本線アイコンがハンバーガーを連想させることからそう呼ばれるようになったようです。

今まで使用してきたMarApps.MetroでもHambergerMenuは存在します。


このHamburgerMenu は動作プラットフォームが表示領域の狭いスマホではなくPC で画面左端のバーが常に表示されていると言う違いはありますが、動作は上図の通り HamburgerMenu に追加したメニューのクリックでアクティブな View を切り替えるような用途に使用できます。

今回はMarApps.MetroのHambergerMenuを使用して実装していきます。


HambergerMenu実装準備

「HambergerMenuとは」で紹介した通り、MarApps.Metroを使用しますのでNuGetで必要なツールをインストールします。


過去の記事「8.OpenCVで画像処理アプリを作ろう(画面デザイン)」でインストール方法を紹介していますので必要あれば確認してみて下さい。

インストール済みの方は読み飛ばしてください。


上記の記事では、「MahApps.Metro.IconPacksをインストールしなくてもよい」記述がありますが、今回は使用するのでインストールしてください。


HambergerMenu実装

実装の流れは、「HambergerMenu用の画面作成」→「HambergerMenu用のViewModel作成」→「MainWindowViewModelの変更」の順でやっていきます。

①MainWindow.xaml

<mah:MetroWindow x:Class="OpenCV_Prism.Views.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:prism="http://prismlibrary.com/"
        prism:ViewModelLocator.AutoWireViewModel="True"
        xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
        xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks"
        xmlns:mns="clr-namespace:OpenCV_Prism.MahAppsHamburgerMenu.Menus"
        Title="{Binding Title}"
        TitleCharacterCasing="Normal"
        Width="auto"
        Height="auto"
        MinWidth="900"
        MinHeight="600">
    <Window.Resources>
        <DataTemplate x:Key="MenuData" DataType="{x:Type mns:HamburgerMenuItemViewModel}">
            <StackPanel Orientation="Horizontal">
                <iconPacks:PackIconControl Kind="{Binding IconKind}"
                                               Margin="8, 10, 30, 10"
                                               Focusable="False"
                                               Width="32" Height="32" />
                <TextBlock Text="{Binding MenuText}"
                           Style="{StaticResource MaterialDesignHeadline6TextBlock}"
                           VerticalAlignment="Center"/>
            </StackPanel>
        </DataTemplate>
    </Window.Resources>
    <mah:HamburgerMenu Grid.Column="0"
                         ItemTemplate="{StaticResource MenuData}"
                         OptionsItemTemplate="{StaticResource MenuData}"
                         ItemsSource="{Binding MenuItems}"
                         OptionsItemsSource="{Binding OptionMenuItems}"
                         PaneBackground="{StaticResource MaterialDesignDarkBackground}"
                         OpenPaneLength="300"
                         SelectedItem="{Binding SelectedMenu.Value, Mode=TwoWay}"
                         DisplayMode="CompactOverlay">
        <mah:HamburgerMenu.Content>
            <Grid>
                <StackPanel>
                    <mah:TransitioningContentControl prism:RegionManager.RegionName="DisplayArea"
                                                     x:Name="ContentRegion"/>
                </StackPanel>
            </Grid>
        </mah:HamburgerMenu.Content>
    </mah:HamburgerMenu>
</mah:MetroWindow>

上記のコードを一部ずつ解説していきます。まずは、 Window.Resources からです。

この部分でHambergerMenuに表示するテンプレートを作成していきます。

Window.Resourcesとは?
WPFでは複数のUI要素で1つのオブジェクトを共有するための仕組みがあり、それをリソースと呼んでいます。リソースを定義しておくと、1つの定義を複数のコントロールで共有できるため、変更が生じた場合も1か所を変更するだけですべてのコントロールに反映されます。StaticResourceとは、定義されたリソースをコントロール等に設定する際に使用します。

下に Window.Resources 部分を抜き取りました。

<Window.Resources>
        <DataTemplate x:Key="MenuData" DataType="{x:Type mns:HamburgerMenuItemViewModel}">
            <StackPanel Orientation="Horizontal">
                <iconPacks:PackIconControl Kind="{Binding IconKind}"
                                               Margin="8, 10, 30, 10"
                                               Focusable="False"
                                               Width="32" Height="32" />
                <TextBlock Text="{Binding MenuText}"
                           Style="{StaticResource MaterialDesignHeadline6TextBlock}"
                           VerticalAlignment="Center"/>
            </StackPanel>
        </DataTemplate>
    </Window.Resources>

x:Key=”MenuData” :Resourcesを呼び出すためのキーワードを設定しています。

DataType 部分ではこのxamlファイルに設定するViewModelを指定しています。このViewModelはまだ設定していません。

StackPanel部分では横の追加していくため、Horizontalを設定しています。

StackPanelで追加するのは、”アイコン”と”テキストボックス”です。それぞれ大きさ、色、スタイルなどを設定しています。

このようにResourcesで設定した項目は、設定したキーワードを使用することで何度も繰り返し使用することができます。


次にHambergerMenuの設定部分を説明します。

    <mah:HamburgerMenu Grid.Column="0"
                         ItemTemplate="{StaticResource MenuData}"
                         OptionsItemTemplate="{StaticResource MenuData}"
                         ItemsSource="{Binding MenuItems}"
                         OptionsItemsSource="{Binding OptionMenuItems}"
                         PaneBackground="{StaticResource MaterialDesignDarkBackground}"
                         OpenPaneLength="300"
                         SelectedItem="{Binding SelectedMenu.Value, Mode=TwoWay}"
                         DisplayMode="CompactOverlay">

mah:HamburgerMenu でHambergerMenuの設定をすることができます。

ItemTemplateでは、表示する内容を指定することができます。

ここで設定しているのは、先ほど DataTemplate で作成した「MenuData」を指定しています。

OptionItemTemplateも上記と同様に「MenuData」を設定しています。ItemTemplateは上から追加していきますが、OptionItemTemplateは下から追加されていきます。

ItemSourcesでは、先ほど指定したMenuDataに紐づく情報のリストを指定していきます。ViewModel側でMenuDataに紐づくデータのリストを追加することでViewなどを作成せずに簡単に繰り返しのViewを表示することができます。

OptionsItemsSource はItemSourcesと同様なので割愛します。

SelectedItem 部分は、HambergerMenuで追加したオブジェクトが選択された情報を取得することができます。

ReactivePropertyでBindingすることで、変更時に通知を受け取ることができ、Subscribeでセレクトする対象に変更があった際の処理を記載することができます。

DisplayMode は、HambergerMenuを選択したと時のmenuの表示方法を設定できます。

いろいろな動作にすることができるので興味がある方は見てみてください。


最後にHambergerMenu.Content部分です。

実行されるメソッドを指定できます。

<mah:HamburgerMenu.Content>
            <Grid>
                <StackPanel>
                    <mah:TransitioningContentControl prism:RegionManager.RegionName="DisplayArea"
                                                     x:Name="ContentRegion"/>
                </StackPanel>
            </Grid>
        </mah:HamburgerMenu.Content>

この部分では、HambergerMenu以外のメイン部分の表示をどうするか設定できます。

そのため、今まで通りPrismのRegionを指定しておきます。

②HamburgerMenuItemViewModelの追加

次にHambergerMenuのViewModelを作成していきます。

using MahApps.Metro.IconPacks;
using Prism.Mvvm;
using Reactive.Bindings;
using Reactive.Bindings.Extensions;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reactive.Disposables;
using System.Text;
using System.Threading.Tasks;

namespace OpenCV_Prism.MahAppsHamburgerMenu.Menus
{
	public class HamburgerMenuItemViewModel: BindableBase
	{
		#region プロパティ

		public object IconKind { get; }

		public string MenuText { get; }

		public string NavigationPanel { get; }

		#endregion

		public HamburgerMenuItemViewModel(object kind, string text, string navigationPanelName)
		{
			this.IconKind = kind;

			this.MenuText = text;

			this.NavigationPanel = navigationPanelName;
		}
	}
}

任意の場所にHamburgerMenuItemViewModelを作成します。

BindableBase継承
まず、ViewModelでは、BindableBaseを継承しています。これは、メモリーリークをさせないために実装しています。DataContext に設定するクラス(通常は ViewModel)が INotifyPropertyChanged を継承していない場合、メモリリークする可能性があるからです。そのため、ViewModelでは必ず BindableBase などを継承してINotifyPropertyChangedを継承するようにしましょう。

プロパティは3つ設定しています。

IconKindは、文字通りアイコンのプロパティです。MahApps.Metro.IconPacksに入っているアイコンはすべて使用することができます。このIconはHambergerMenuをクリックする前から表示されています。Objectにしている理由は、特にIconの種類を特定していないためです。そのため、なんでも入るObjectにしています。

MenuTextは、以下の写真のようにIconの説明を示します。HambergerMenuをクリックした後に表示されます

NavigationPanelは、このボタンに紐づくModelの名前を入れていきます。作成しているアプリでは、ボタンを押すと画像処理内容を変更していくため、ImageThresholdなどのModel名を入れていきます。

また、コンストラクタでは、それぞれの値が格納されるように設定してあります。

※すみません、予想以上に記事が長くなっているので記事を2編構成にします。


まとめ&次回予告

今回は、HambergerMenuの実装を途中まで行いました。

長くなるので次回から続きを記事にして説明していきます。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です