[Xamarin.CrossPlatform] マスタ/詳細アプリのプロジェクトを理解する1

数回に分けて、Xamarinのマスタ/詳細型アプリのプロジェクトについて理解を含めていきます。

今回はマスタ/詳細型プロジェクトの技術要素について見ていきます。

WindowsのVSはEnterprise 2017 Ver.15.5.2
MacのVSは7.3.2

を使用しています。

マスタ/詳細型プロジェクトの作成方法

クロスプラットフォームのアプリを作成する場合、WindowsのVisual StudioでもMacのVisual Studioでも、2つのテンプレートから作成することになります。

1つは空白のフォームのテンプレート、もう1つはマスター/詳細型のテンプレートです。

以下にプロジェクト作成時のダイアログを示します。上がWindows版で下がMac版です。

Windows版は、Master Detailを選択するとマスタ/詳細型のアプリを作成することができます。ちなみにBlank Appを選択すると空白のフォームアプリを作成することができます。

Mac版は、フォームアプリを選択することでマスタ/詳細型のアプリを作成することができます。

Windows版、Mac版とも、作成されるファイルは同じです。以降スクショはMac版を掲載します。

MVVM

マスタ/詳細型のプロジェクトは、MVVMパターンです。

MVVMはModel-View-ViewModelの略で、GUIを持つアプリケーションをModel、View、ViewModelの3つに分割して設計、実装を行います。

これはMVC(Model-View-Controller)の派生パターンになっています。

Model

Modelはビジネスロジック(アプリケーションのデータと手続き)を担う部分です。このため、表示機能については関与しませんが、背景色や文字色といった装飾部分のデータについてはModelで管理します。

View

Viewはデータを見える形にして表示したり、ユーザーからの入力を受け取る部分を担当します。Viewには複雑なロジックを持たせることはしません。基本的にはデータバインディング(後述)と呼ばれる機構を使用して、データの表示や入力の受け取りを行うようにします。

ViewModel

ViewModelはViewから受け取ったデータをModelに伝達したり、Viewの状態保持を担当します。このようにViewModelはViewとModelの仲介役となります。

データバインディング

データバインディングはUIとデータを関連付ける機構です。XamarinのCrossPlatform開発においては、Xamlの中にバインディング用の属性を記述することで、Modelが持つデータを自動で表示したり、ユーザーが入力したデータを受け取ることができるようになります。

 

今回は、マスタ/詳細型のプロジェクトの基本技術要素について触れてきました。文字ベースですし、説明がわかりにくいとことろもあるかと思います。

次回以降は、実際のコードも掲載しながら理解を進めていきます。

[Xamarin.Mac] View Controller間でデータを受け渡すには

前回の記事では、View Controllerをコードから表示する方法について紹介しました。

今回は、View Controller間でのデータの受け渡し方法について見ていきましょう。

1.メインウィンドウの作成

はじめに新規でプロジェクトを作成して、メインウィンドウにButtonを1つ、その下にText Fieldを1つ貼り付けます。

続いて、貼り付けたButtonのアクション接続を作成します。アクション名は「showSubView」とします。

次に、貼り付けたText Fieldのアウトレット接続を作成します。接続名はfirstTextとしてください。

アクション接続とアウトレット接続の作成方法については「シンプルなアプリを作ってみよう 〜アクションとアウトレット〜」を参照ください。

作成したアクション接続とアウトレット接続のコードを以下に示します。

#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>


@interface ViewController : NSViewController {
    NSTextField *firstText;
}
- (IBAction)showSubView:(id)sender;
@property (assign) IBOutlet NSTextField *firstText;

@end

2.サブウィンドウの作成

続いて、もう1つView Controllerを配置します。

このView ControllerにもButtonとText Fieldを配置します。

次にView Controllerを選択してCustom Classに「SecondViewController」と入力して[return]キーを押し、[command]+[s]で上書き保存をします。この操作によってサブウィンドウ用のクラスが作成されます。このクラスはNSViewControllerを継承しています。

次にアシスタントエディタでSecondViewController.hを開いておき、今配置したText Fieldのアウトレット接続を作成します。アウトレット接続の名前はsecondTextとしてください。

またButtonのアクション接続も作成します。アクション接続名はsubViewCloseとします。

SeconViewController.hのコードは以下のようになります。

#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>

@interface SecondViewController : NSView {
    NSTextField *secondText;
}
@property (assign) IBOutlet NSTextField *secondText;
- (IBAction)subViewClose:(id)sender;

@end

ここまでできたら[command]+[s]を押して、Visual Studioへ戻ります。

3.セグエの作成

続いてセグエを作成しましょう。メインウィンドウからサブウィンドウに向かってドラッグ&ドロップし、セグエを作成します。表示されたManual SegueのダイアログではModalを選択することとします。

次に作成したSegueを選択して「MySegue」という名前を付けます。あとで、この名前でコードからサブウィンドウを開けるように作成します。

4.メインウィンドウのコードを作成する

続いてメインウィンドウのコードを作成するのですが、その前にサブビュー側でメインウィンドウから渡された値を受け取ることができるプロパティを作成しておきましょう。

Visual StudioでSecondViewController.csを開いて、以下のように、TextValueというプロパティを追加します。

// This file has been autogenerated from a class added in the UI designer.

using System;

using Foundation;
using AppKit;

namespace WindowSample5
{
  public partial class SecondViewController : NSViewController
  {
    // メインウィンドウから受け取る値用のプロパティ
    public string TextValue { get; set; }

    public SecondViewController (IntPtr handle) : base (handle)
    {
    }
  }
}

次に、ViewController.csを開いてメインウィンドウのコードを以下のように入力します。

using System;

using AppKit;
using Foundation;

namespace WindowSample5
{
  public partial class ViewController : NSViewController
  {
    public ViewController(IntPtr handle) : base(handle)
    {
    }

    public override void ViewDidLoad()
    {
      base.ViewDidLoad();

      // Do any additional setup after loading the view.
    }

    public override NSObject RepresentedObject
    {
      get
      {
          return base.RepresentedObject;
      }
      set
      {
          base.RepresentedObject = value;
          // Update the view, if already loaded.
      }
    }

    // ここから追加コード

    // Buttonクリック時の処理
    partial void showSubView(NSObject sender)
    {
      // Segueでサブビューを表示
      PerformSegue("MySegue", this);
    }

    // Segueでサブウィンドウが開かれる前に実行されるメソッド
    public override void PrepareForSegue(NSStoryboardSegue segue, NSObject sender)
    {
      base.PrepareForSegue(segue, sender);

      // サブウィンドウのインスタンスを取得
      SecondViewController sv = segue.DestinationController as SecondViewController;
      // サブウィンドウのプロパティに値をセット
      sv.TextValue = this.firstText.StringValue;
    }

    // サブウィンドウから呼び出してメインウィンドウのText Fieldに値をセットするメソッド
    public void SetTextValue(string textValue)
    {
        this.firstText.StringValue = textValue;
    }
  }
}

Buttonには、showSubView というアクション接続を作成したので、partial void showSubView というメソッドを追加しています。このめそっどの中では PerformForSegue メソッドを使用してサブウィンドウを開きます。

サブウィンドウを開く前に値を渡したいので、PrepareForSegue というメソッドをオーバーライドして追加しています。このメソッドは、セグエが実行される前に起動して処理が行われます。よってメソッドの中では、サブウィンドウのインスタンスを取得して、サブウィンドウのプロパティである TextValue にメインウィンドウの Text Field の値を設定しています。

最後に、サブウィンドウからメインウィンドウへ値をセットできるようにするために SetTextValue というメソッドを追加しています。引数で受け取った値をメインウィンドウのText Fieldに設定しています。

5.サブビューのコードを作成する

最後ににサブビュー側のコードを作成しましょう。

ソリューションエクスプローラーで SecondViewController.cs をダブルクリックして開き以下のようにコードを入力します。

// This file has been autogenerated from a class added in the UI designer.

using System;

using Foundation;
using AppKit;

namespace WindowSample5
{
  public partial class SecondViewController : NSViewController
  {
    // メインウィンドウから受け取る値用のプロパティ
    public string TextValue { get; set; }

	public SecondViewController (IntPtr handle) : base (handle)
	{
	}

    // ここから追加コード
    public override void ViewDidLoad()
    {
      base.ViewDidLoad();

      // Text Fieldにメインウィンドウから受け取った値をセット
      this.secondText.StringValue = this.TextValue;
    }

    partial void subViewClose(NSObject sender)
    {
      // メインウィンドウのインスタンスを取得
      ViewController vc = this.PresentingViewController as ViewController;
      // メインウィンドウのメソッドを呼び出して、サブウィンドウのText Fieldの値を渡す
      vc.SetTextValue(this.secondText.StringValue);
      // サブウィンドウを閉じる
      this.View.Window.Close();
    }
  }
}

オーバーライドした ViewDidLoad は、画面が開かれたときに初期化をするメソッドです。ここでは、メインウィンドウから受け取った値が入っている TextValue プロパティを、Text Fieldに設定しています。これによりサブウィンドウが開いたときに、メインウィンドウから受け取った値が Text Field に表示されます。

subViewClose というメソッドは Button がクリックされたときに実行されるメソッドです。この中ではメインウィンドウのインスタンスを取得して、SetTextValue というメソッドを使用して、サブウィンドウのText Fieldの値を渡しています。最後に Close メソッドを実行してサブウィンドウを閉じます。

6.実行してみよう

それでは実行して確認をしてみましょう。

メインウィンドに「メインウィンドウの値」と入力してButtoonをクリックすると、サブウィンドウが表示されText Fieldには「メインウィンドウの値」と表示されます(上がメインウィンドウ、下がサブウィンドウの図です)。

次にサブウィンドウのText Fieldに「終了」と入力してButtonをクリックすると、サブウィンドウが閉じられてメインウィンドウのText Fieldに「終了」が表示されます(上がサブウィンドウ、下がメインウィンドウの図です)。

 

[Xamarin.Forms] Jsonファイルを使用する(3)

前回の「Jsonファイルを使用する(2)」では、Json.NetのNuGetパッケージを追加し、デシリアライズ用のクラスを作成しました。

今回は、最終仕上げとしてデシリアライズをする方法を見ていきます。

アジェンダは以下の通りです。

  1. usingの追加
  2. デシリアライズコードの作成

1.usingの追加

はじめに、共通プロジェクト(JsonSample)のJasonSamplePage.xaml.csを開きます。

usingを以下のようにし、Json.Netとデシリアライズをできるようにしておきます。

using System.IO;
using System.Reflection;
using Newtonsoft.Json;
using Xamarin.Forms;

2.デシリアライズコードの作成

あとはプロジェクトに組み込んだperson.jesonを読み込んでデシリアライズをしPersonクラスのインスタンスにデータを入れるコードを書きます。

namespace JsonSample
{
    public partial class JsonSamplePage : ContentPage
    {
        public JsonSamplePage()
        {
			var assembly = typeof(JsonSamplePage).GetTypeInfo().Assembly;
			Stream stream = assembly.GetManifestResourceStream("JsonSample.person.json");

			Person[] persons;


			using (var reader = new System.IO.StreamReader(stream))
			{

				var json = reader.ReadToEnd();
				var rootobject = JsonConvert.DeserializeObject<Rootobject>(json);

				persons = rootobject.persons;
			}
        }
    }
}

7行目は、person.jsonファイルがどこにあるかの情報を取得するものです。typeofの()の中には、このコードが書かれているクラス名を書いています(このコードを書いているクラスはJsonSamplePageというクラスです)。必要に応じて変更して下さい。

8行目は、プロジェクトに追加したperson.jsonのストリームを取得する処理です。GetManifestResourceStreamの引数には、「プロジェクト名.JSONファイル名」を書きまます。

す。

10行目は、デシリアライズ先の変数の準備です。person.jsonは複数のperson情報を持っているので配列にしています。

13行目は、ストリームリーダーのインスタンスを生成して、person.jsonを読み取る準備をしています。

16行目で、peson.jsonからjsonデータを取得し、17行目でデシリアライズをしています。DeserializeObjectの<>にはデータを受け取る器(うつわ)の型を指定するので、前回作成したRootobjectを指定します。また引数にはデシリアライズの元)である(16行目で受け取ったpersonを指定します。

最後に、17行目でデシリアライズ結果を受け取ります。

以上で、プロジェクトに組み込んだjsonファイルからのデータ取得が完了です。あとはpersons変数に入っているデータを使用するのみとなります。