[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変数に入っているデータを使用するのみとなります。

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

前回の記事「Jsonファイルを使用する(1)」では、JSONファイルを作成し、プロジェクトに組み込むまでを説明しました。

今回は、JSONファイル操作を行うNuGetパッケージの追加と、デシリアライズするためのクラスの作成を行います。

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

  1. JSON用のNuGetパッケージの追加
  2. シリアライズとデシリアライズ
  3. デシリアライズ用クラスの作成

1.JSON用NuGetパッケージの追加

Xamarin.FormsでJSONファイルを操作するには、ライブラリを使用します。標準のライブラリを使用しても行えますが、もっと便利なライブラリ(NuGetパッケージ)を使用します。

Windows版のVisual Studioを使用している場合は、メニューの[ツール]-[NuGetパッケージマネージャー]-[ソリューションのNuGetパッケージの管理]をクリックして下さい。

NuGetソリューションの画面に切り替わるので、「参照」を選択して「Json.Net」

を検索します。検索結果から「newtonsoft.Json」を選択して[インストール]ボタンをクリックして下さい。

Mac版Visual Studioの場合は、共通プロジェクト(PCLプロジェクト)を右クリックして[追加]-[NuGetパッケージの追加]を選択します。

検索窓で「Json.Net」を入力して検索をし、一覧から「Json.Net」にチェックを付けます。最後に[パッケージを追加]をクリックします。

2.シリアライズとデシリアライズ

はじめに、シリアライズとデシリアライズの用語についておさらいしておきましょう。

シリアライズは、クラスの内容をある形式のファイルに変換することです。例えば、personというクラスがあり、このクラスが持つデータの内容から、XMLやJSON形式のファイルを作成することをシリアライズ化と呼びます。

一方デシリアライズは、シリアライズ操作の逆です。あるファイルの内容から、クラスにデータをセットすることをデシリアライズと呼びます。

先ほど組み込んだJson.Netは、JSONファイルのシリアライズ/デシリアライズを行うための機能を持っています。この機能を使用することで、容易にシリアライズもデシリアライズも行うことができます。

今回の一連の記事では、プロジェクト内に配置したperson.jsonというファイルの内容をクラスに展開したいので、デシリアライズを行います。

3.デシリアライズ用クラスの作成

はじめに、前回作成したperson.jsonのおさらいをしておきましょう。

{
  "persons": [
    {
      "Name": "HIRO",
      "Age": 44,
      "Gender": "Male"
    },
    {
      "Name": "Bill",
      "Age": 53,
      "Gender": "Male"
    },
    {
      "Name": "Cathy",
      "Age": 38,
      "Gender": "Female"
    },
  ]
}

personsという配列があり、その中にName, Age, Genderのデータを持っているJSONファイルです。

このファイルの内容を保持できるクラスは、Nameプロパティ(String型)、Ageプロパティ(int型)、Genderプロパティ(String型)を持っていればよいことがわかります。JSONファイルではpersonsという配列がありますが、これはクラスのインスタンスを配列化すれば対応が可能です。よってシンプルにName, Age, Genderのプロパティを持つクラスを作成します。

以上を理解できたら、共通のプロジェクト(JsonSample)に「Personクラス」を作成してください。

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string Gender { get; set; }
}

Xamrinのサイトのサンプルでは、上記のようなクラスの配列をプロパティとして持つクラスを作成して管理しています。例にならって、Rootobjectというクラスも作成することにします。

public class Rootobject
{
    public Person[] persons { get; set; }
}

以上でデシリアライズ用クラスの作成は完了です。

次回は、いよいよデシリアライズを行う方法について説明します。