Xamarin
Xamarin.Forms

Xamarin.Forms の MasterDetail を実装してみよう

More than 1 year has passed since last update.

【更新】Visual Studio 2017 の場合

  • MasterDetailPage とその他諸々をソリューションに追加してくれるテンプレート Forms MasterDetail Page Xaml が VS2017 で追加されました。
  • 説明は以上です。ありがとうございました :smile:
  • 【注意】VS2017 のプロジェクト テンプレート クロスプラットフォーム アプリ (Xamarin.Forms またはネイティブ)マスター/詳細 を選択しても MasterDetailPage クラスは使用されません。 (Bug 53141)

方針

  • Xamarin 公式ページになるべく従って
  • C# コードではなく xaml の方で
  • Droid と iOS
  • 私が引っかかったところを補足していきます
  • 自分で作るクラスがどれか分かりにくいので My を付けていきます

公式

developer.xamarin.com/guides/xamarin-forms/user-interface/navigation/master-detail-page/


環境

  • Visual Studio 2015 update 3
  • Xamarin 4.2.x.x

プロジェクト

  • Blank Xaml App (Xamarin.Forms Portable) MyApp を作成
  • WindowsWinPhone プロジェクトを削除(ゴメンナサイ)

最初のビルド

Welcome to Xamarin Forms!


MyMasterDetailPage.xaml

Forms Xaml Page MyMasterDetailPage を追加


<?xml version="1.0" encoding="utf-8" ?>
<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms"
                  xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                  xmlns:local="clr-namespace:MyApp;assembly=MyApp"
                  x:Class="MyApp.MyMasterDetailPage">
  <MasterDetailPage.Master>
    <local:MyMasterPage />
  </MasterDetailPage.Master>
  <MasterDetailPage.Detail>
    <NavigationPage>
      <x:Arguments>
        <local:MainPage />
      </x:Arguments>
    </NavigationPage>
  </MasterDetailPage.Detail>
</MasterDetailPage>

  • .cs で派生親を ContentPage から MasterDetailPage に変更するのを忘れないこと
  • MasterDetailPage を作るテンプレートがあってもいいのに
  • デザインの情報がほとんど無いのに xaml で作るのって回りくどくないですか...
  • Detail 役は MainPageWelcome to Xamarin Forms! のページ)で済ませました
  • Master 役はこのあと作ります

MyMasterPage.xaml

  • Forms Xaml Page MyMasterPage を追加

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MyApp.MyMasterPage"
             Padding="0,40,0,0"
             Icon="hanburger.png"
             Title="メニュー">
  <StackLayout VerticalOptions="FillAndExpand">
    <ListView x:Name="listView" VerticalOptions="FillAndExpand" SeparatorVisibility="None">
      <ListView.ItemTemplate>
        <DataTemplate>
          <ImageCell Text="{Binding Title}" ImageSource="{Binding IconSource}" />
        </DataTemplate>
      </ListView.ItemTemplate>
    </ListView>
  </StackLayout>
</ContentPage>

  • Master 役
  • 派生親は ContentPage のままで OK
  • hamnurger.pngSample Code から落としてきて Droid と iOS の両方に追加する
  • Padding="0,40,0,0" をサボると1番上のアイテムが画面上部の OS の操作と干渉する
  • ContentPage.Content は省略できると思います

MyMasterPage.xaml.cs


using System.Collections.Generic;
using Xamarin.Forms;

namespace MyApp
{
  public partial class MyMasterPage : ContentPage
  {
    public MyMasterPage()
    {
      InitializeComponent();

      var myMasterPageItems = new List<MyMasterPageItem>();
      myMasterPageItems.Add(new MyMasterPageItem
      {
        Title = "ようこそ",
        IconSource = "icon.png",
        TargetType = typeof(MainPage)
      });
      listView.ItemsSource = myMasterPageItems;
    }
  }
}


  • リストの中身を準備するところ
  • 画像は Droid にある icon.png でゴマカす(iOS 側にも icon.png を追加する)
  • x:Name="listView" と書けば .cs で listView が使えるようになるのはうれしい
  • MyMasterPageItem はこのあと作る

MyMasterPageItem.cs

  • クラス MyMasterPageItem を追加
  • Sample CodeMasterPageItem.cs からメンバーの定義をコピペ

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MyApp
{
  public class MyMasterPageItem
  {
    public string Title { get; set; }
    public string IconSource { get; set; }
    public Type TargetType { get; set; }
  }
}

  • ListView のアイテム
  • public にするのを忘れない
  • 自分で作らないといけないクラスなのに説明が無いのはちょっと不親切では...
  • Type 型とかスラスラ出てきません...

App.xaml.cs

  • 最初に開く画面を変える
  • これを変えないと Welcome to Xamarin Forms! のまま

    public App()
    {
      InitializeComponent();

      //MainPage = new MyApp.MainPage();
      MainPage = new MyMasterDetailPage();
    }

一旦ビルド

  • ここで一旦ビルドが通る
  • 実行すると Master は出てくるけど、タップしても何も起きない状態

タップの実装

MyMasterPage.xaml.cs

  • Master の ListView を公開

  public partial class MyMasterPage : ContentPage
  {
    public ListView ListView { get { return listView; } }
    ...

MyMasterDetailPage.xaml

  • Master に名前を付ける

<MasterDetailPage ...>
  <MasterDetailPage.Master>
    <local:MyMasterPage x:Name="masterPage" />
  </MasterDetailPage.Master>
  ...
</MasterDetailPage>

MyMasterDetailPage.xaml.cs

  • MasterDetailPage にイベント処理を記述

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Xamarin.Forms;

namespace MyApp
{
  public partial class MyMasterDetailPage : MasterDetailPage
  {
    public MyMasterDetailPage()
    {
      InitializeComponent();
      masterPage.ListView.ItemSelected += OnItemSelected;
    }

    void OnItemSelected(object sender, SelectedItemChangedEventArgs e)
    {
      var item = e.SelectedItem as MyMasterPageItem;
      if (item != null)
      {
        Detail = new NavigationPage((Page)Activator.CreateInstance(item.TargetType));
        masterPage.ListView.SelectedItem = null;
        IsPresented = false;
      }
    }
  }
}


  • MasterDetailPage から Master の中に手を突っ込むのは気持ち悪くないですか...

最後のビルド

  • 動くぞ :o
  • ついでに ListView の書き方も分かった
  • 公式の最後の MasterBehavior をいじる話はオマケ