F# から Fortarn の関数を呼び出そう

この記事は F# Advent Calendar 2014 の 14日目の記事です。今回は英語版もあるそうで、以下から辿っていくと英語版の F# Advent にたどり着けます(当然、中身が英語ですね)。

F# Advent Calendar 2014 – connpass
http://connpass.com/event/9758/
F# Advent Calendar in English 2014 | Sergey Tihon’s Blog
http://sergeytihon.wordpress.com/2014/11/24/f-advent-calendar-in-english-2014/

さて、去年は F#とFortranの話…のその前に というのを書いて、あえなく挫折したワタクシですが、今回は F# から Fortran を呼び出すことに成功致しましたッ!!! って、誰得な技術情報なのですが、いちおう、頭が F つながりというネタ記事なので、お許しを(笑)。

Fortarn で DLL を作成する

DLL は Intel Visual Fortran 2013 を使っています。

Intel の Fortran では、DLL を作成できて、以下のように「!DEC$ ATTRIBUTES DLLEXPORT::<公開名>」のように、DLL で公開する関数を定義できます。gcc にも fortran があるのですが、そっちのほうはスタティックライブラリしか作ったことがなくて、よくわかりません。ただし、linux 上で動かすのならば *.so ファイルを作ってそのまま C 言語から使えるようにできるので、おそらく F# からも似たような形で作れるでしょう。
まあ、Windows 上ならば DLL なので、このスタイルで。

! 数値を渡す簡単なパターン
integer function add1( a, b )
    !DEC$ ATTRIBUTES DLLEXPORT::ADD1
    integer, intent(in) :: a, b
    integer :: total

    total = a + b
    add1  = total
end function add1

! 1次元配列を渡す
integer function sum1( v, count )
    !DEC$ ATTRIBUTES DLLEXPORT::SUM1
    integer, intent(in) :: v(10)
    integer, intent(in) :: count
    integer :: i, total

    total = 0
    do i=1,count
        print *, 'in sum1: ', i, v(i)
        total = total + v(i)
    end do
    sum1 = total
    end function sum1

! 二次元配列を渡す
integer function sum2( v, cnti, cntj )
    !DEC$ ATTRIBUTES DLLEXPORT::SUM2
    integer :: v(3,4)
    integer :: cnti, cntj
    integer :: i,j
    integer :: total

    total = 0
    do j=1,cntj
        do i=1,cnti
            print *,i,j,v(i,j)
            total = total + v(i,j)
        end do
    end do
    sum2 = total
end function sum2

Fortran の中身がチープすぎますが、数値(int型)と配列を試してます。あと実用的にするには、double, float あたりを試しておく必要がありますね。

まずは、試しに C++ から呼び出す

動作確認をするために C++ から呼び出してみましょう。Fortran から公開されれる DLL 関数は、dllimport を使って呼び出せるのですが、値を渡すところがポインタになっているところが注意したいところです。これ Fortran の関数渡しがスタック経由ではなくてグローバル変数経由だからなんですよね。C 言語の場合スタックに値を積んで渡します(C#などの.NET言語から渡すときも同じ)が、Fortran に渡すときは、これに注意しないといけないという、変な感じなのです。まあ、Fortran だけでやっているときは、あんまり考慮しなくてよくて便利(でかい配列をそのまま渡すとか)なので、良し悪しということで。

#include "stdafx.h"
#include <iostream>

#define DllImport __declspec( dllimport )

extern "C" {
	DllImport int ADD1(const int *, const int *);
	DllImport int SUM1( int(*)[] , const int *);
	DllImport int SUM2(int(*)[4][3], const int *, const int *);
}

int _tmain(int argc, _TCHAR* argv [])
{
	int x = 10;
	int y = 20;
	int ans = ADD1(&x, &y);
	std::cout << "ans " << ans << std::endl;

	int  v[] = { 1, 2, 3, 4, 5 };
	int cnt = 5;
	int ans2 = SUM1((int(*)[])&v, &cnt);
	std::cout << "ans2 " << ans2 << std::endl;

	int v2[][3] = {
		{1,2,3},
		{11,22,33},
		{10,20,30},
		{100,200,300}
	};
	int cnti = 3;
	int cntj = 4;
	int ans3 = SUM2( &v2, &cnti, &cntj);
	std::cout << "ans3 " << ans3 << std::endl;

	return 0;
}

実行すると、こんな感じになります。

C# から呼び出してみる

これを C# で書き直してみましょう。DllImport を使うのは分かったのですが、int のポインタを渡さないといけないので、ref を使います。関数の呼び出し形式は、明示的に CallingConvention = CallingConvention.Cdecl を定義する必要があります。

class Program
{
	[DllImport("FModule.dll", CallingConvention = CallingConvention.Cdecl)]
	extern static int SUM1([In] int[] v, [In] ref int count);
	[DllImport("FModule.dll", CallingConvention = CallingConvention.Cdecl)]
	extern static int SUM2([In] int[,] v, [In] ref int cnti, [In] ref int cntj);
	[DllImport("FModule.dll", CallingConvention = CallingConvention.Cdecl)]
	extern static int ADD1([In] ref int a, [In] ref int b);

	static void Main(string[] args)
	{
		int a = 10;
		int b = 20;
		int ans = ADD1(ref a, ref b);
		Console.WriteLine("ans {0}", ans);

		int[] v = { 1, 2, 3, 4, 5 };
		int cnt = v.Length;
		int ans2 = SUM1(v, ref cnt);
		Console.WriteLine("ans2 {0}", ans2);
		/*
		int[][] v2 = {
							new int[]{1,2,3,4},
							new int[]{11,22,33,44},
							new int[]{10,20,30,40},
						};
		*/
		int[,] v2 = {
						{1,2,3},
						{11,22,33},
						{10,20,30},
						{100,200,300},
					};
		int cnti = 3;
		int cntj = 4;
		int ans3 = SUM2(v2, ref cnti, ref cntj);
		Console.WriteLine("ans3 {0}", ans3);
	}

2次元配列を渡すときは、int[][] ではなくて int[,] を使います C++ や Fortran と同じように連続したメモリに int 値が配置されるようにするためです。ADD1 関数を呼び出すときに ref を付けるのが面倒なのですが、これで Fortran の DLL を正しく呼び出せます。

F# から呼び出してみる

更に F# に書き換えてみましょう。dll から export されているポインタは int& のように宣言します。

open System
open System.Runtime.InteropServices

type ARY2D = int[,]

[<AutoOpen>]
module FDLL =
  [<DllImport("FModule.dll", CallingConvention = CallingConvention.Cdecl)>]
  extern int ADD1(int& a, int& b)
  [<DllImport("FModule.dll", CallingConvention = CallingConvention.Cdecl)>]
  extern int SUM1(int[] v, int& count )
  // int[,] がそのままでは渡せないので alias を作って指定する
  [<DllImport("FModule.dll", CallingConvention = CallingConvention.Cdecl)>]
  // extern int SUM2(int[,] v, int& cnti, int& cnt2 )
  extern int SUM2(ARY2D v, int& cnti, int& cnt2 )

let mutable a = 10
let mutable b = 20
let ans = ADD1( &a , &b )

Console.WriteLine( "ans {0}", ans )

let mutable v = [|1;2;3;4;5|]
let mutable cnt = v.Length
let ans2 = SUM1( v, &cnt )

Console.WriteLine( "ans2 {0}", ans2 )

// 二次元配列は Array2D で作る
let vv = [|
    [|1;2;3|];
    [|11;22;33|];
    [|10;20;30|];
    [|100;200;300|];
  |]
let v2 = Array2D.init 4 3 ( fun i j -> vv.[i].[j])

let mutable cnti = 3
let mutable cntj = 4
let ans3 = SUM2( v2, &cnti, &cntj )

Console.WriteLine( "ans3 {0}", ans3 )

C# と比べて簡素に書ける…ほどではなくて、あまり変わりませんね。それよりも、気になるのは const で渡したいのに let mutable を使わないといけないところです。これは Fortran の呼び出しの制約で、値のポインタを渡すために、内容が変更されなくても a の変数は mutable にしないと渡せないのです。ここはひと工夫したいところです。せっかくの immutable な値なのに、ってところです。
あと、C# での2次元配列 int[,] を F# でどうやって書くのか不明だったので…すが、方法が解りました。Array2D を使うと int[,] 相当なものが作れます。これで、もう一工夫必要なのは extern するときに int[,] で型指定ができないので、alias を作ります。ここでは、ARY2D という型 alias を作って extern int SUM2( ARY2D v, … ) としています。こうすると、C++ と同じように2次元配列として渡せるようになります。

実行した結果は 2次元配列の向きが C++ と逆になっていますが、まあ、こっちのほうが分かりやすいかなと。Xij のほうが X[j,i] よりも書きやすいかなと思います(いや、単純に順番を間違えただけなんですけどね)。

まとめ

というわけで、1年越しの案件?として、F# から Fortran を扱うネタ記事ができました。これで、既存の Fortran ライブラリを F# から作ったアプリが作れますね…っていうか、誰得な技術情報なのですが、いやあ、やってみたかったということで。皆様、よいクリスマスをッ!!!

カテゴリー: F#, Fortran | 1件のコメント

RealSense 事始め

RealSense App Challenge 2014 – Intel
http://japan.intel.com/realsense/

というのがあって、無事ステップ1を通過して、無事先日 RaelSense の実機が届いたので色々と実験中です。2月末ぐらいまでにアプリを作って提出しないといかんのですが(参加賞っぽい≒数が多いという意味での mini pc ぐらいは貰えるぐらいまでは頑張らんと)、スタートダッシュはできなかった(するつもりはなかった)ので、ちまちまと。

機器自体は、まだ製品化前?かつ、SDKもベータ版なのですが、一通り C++/C#/Java のサンプルが付いていて、ひと通り動かすことができます。開発環境が Windows 8.1 Update 64bit 版 かつ USB 3.0 ポートがある PC ということなので、それなりにスペックの高い PC(あるいはノートPC)を用意しないといけないかなと。

Intel® RealSense™ SDK | Intel® Developer Zone
https://software.intel.com/en-us/intel-realsense-sdk

とはいえ、手元の白 vaio S シリーズで、そこそこ動いているので(顔認識させているときとかの CPU パワー喰いはすごいですが)そこまで高スペックでなくてもよいかもしれません。なお、ツイッターで検索すると RealSense をやっているのは私のほかに @saka_pon さんと @hatsune_ @yukio_saitoh さんとぐらいです。潜在的にはもっといるような気がしないでもないのですが、まあコンテストだからこんなぐらいかもしれません(全世界で3000人ぐらいだから、日本に50人ぐらいいても不思議ではないと思うのですが)。

https://pbs.twimg.com/media/B4JNfSvCcAAlMCF.jpg:large

RealSense で何ができるのか?はさておき、SDK をみてみると、普通の USB カメラでも動く機能ついてきます。Device が RealSense のカメラだけじゃなくて、USB カメラであれば何でもいいので、上記のように表情のトラッキングアプリも動きます。このサンプルは RealSense SDK の中に入っているもので、ソース付きなのでそのまま自作アプリに組み込めます(とはいえ、64bit 限定だしベータ版なのですが)

image

画像データ自体は、PXCMImage という独自形式になっていますが、拡張メソッドの ToBitmap が提供されていて、これをピクチャーボックスに fps 単位で描画することで動画のようにみせています。単純な Bitmap の切り替えなので、文字の重ね合わせとかが楽になりそうで助かります。raw_streams というサンプルに PXCMBitmap クラスがあって、PXCMImage から Bitmap へ変換しています。サンプルのほうも C++ よりも C# のほうが UI がリッチになっている(Unity は持ってないのでわからないです)のが時代の進歩を感じさせます。ちょっと前までは C++ のほうがきれいな UI(あるいは豊富な機能)を用意したものですが、おそらく C# のサンプルを作って C++ サンプルが後追いになっていると思われます。

私の場合は、主にオブジェクトトラッキングとオブジェクト認識のところを攻めてアプリに仕上げる予定なのですが、RealSense SDK 自体のオブジェクトトラッキングで足りない部分は、OpenCV で補います。このときに、C# から使える OpenCvSharp を使うのと、同じように Cv.Mat から Bitmap へ変換できる機能を利用していきます。

同時に、アプリの UI は WPF で作ります。そうすると、文字や他のコントロールとの重ね合わせが非常に楽になります。Visual Studio 上でレイアウトをアレンジできるし、既存の WPF コントロールを使ってエフェクトを作れますからね。その場合も、先の OpenCvSharp にある WritableBitmap の機能や、Bitmap の相互変換機能を使います。

そんな訳で、このあたりの Bitmap の相互変換ができるとアプリ作りがやりやすいので、そのあたりが手を付けていこうと思っているところ。

カテゴリー: RealSense | RealSense 事始め はコメントを受け付けていません

プロ生ちゃん Hidden Object ゲームを作ろう…の途中

プロ生ちゃん Advent Calendar 2014 – Qiita
http://qiita.com/advent-calendar/2014/pronama-chan

の8日目の記事です。Xamarin+F# とダブってしまったので、ゲーム自体ができていません…という訳ではなくて、マスコットアプリ文化祭 2014 もかねて作る予定だったのですが、なんかあれこれと体調が悪くて、できあがりそうにないので、構想と途中経過だけでもつらつらと。

マスコットアプリ文化祭 2014 (Mascot Character Apps Contest)
http://pronama.github.io/mascot-apps-contest/2014/

Hidden Object Game とは?

Online Hidden Object Games | Big Fish
http://www.bigfishgames.com/online-games/genres/15/hidden-object.html

単純に絵に隠されたモノを探すゲームです。ブラウザでもPCネイティブでもあるのですが、リアルっぽい絵の中に、リアルっぽいコインやら壺やら剣やらが隠されているので、探して見つけ出します。リストにある(英語なんだけど)名前のものを探してクリックする単純なゲームなんですが、なぜかブラウザゲームの1ジャンルを占めています。たぶん、探すとそれなりに時間がかかるので暇つぶしにいいのと、ゲームのお試し時間(1時間など)に挟み込んで、お試し時間を食いつぶすのにちょうどいいんですよね。このゲーム方式。
Hidden Object Game を解くアルゴリズム…を考えるのも面白そうなのですが、今回は、Hidden Object を作るほうのアルゴリズムを考えてみます。

たぶん、公開されているゲームは、背景の絵に人の手でちまちまと隠れそうな場所を選んでおいていると思うのですが、それを自動化します…自動化して何かいいことがあるのか?汎用性はあるのか?ってのもあるけど、まあ自動化する方法を考えてみましょう。その経緯で得られるものは多いですからね。

隠れるとはどういうことか?

最初に「隠れる」とはどういうことかを考えておきましょう。Hidden Object では、モノを隠すときに単純に絵に重ねています。半透明になって判別しづらい状態になっています。ちょうど背景の形に沿っていたり、背景の色に揃っていたりします。絵本などのローリーを探せのような探しものは、(人の意志で)あらかじ絵に埋め込まれていますが、Hidden Object の場合は、あらかじめ背景があるところに(人の意志で)見つけにくくなるように重ね合わせをします。
同時に、完全に重ね合わせて隠れてしまってはいけません。きちんと、見つかるように微妙な違いは残しておく必要があります。そうしないと、見つからないかくれんぼになってしまうので、いつになっても終わりになりません。

これが、無造作に渋谷の街並みにプロ生ちゃんを半透明に隠した状態です。半透明にしているだけだから、隠れているといえば隠れているし、無造作に置いているだけなので、隠れていないといえば隠れていません。すぐ見つけられます。

特徴量をみてみよう

この「隠れる」という定義を考えなおしてみましょう。(いきなしですが)コンピュータビジョン的なところでいえば、物がわかる(物体を認識する)という方法、主に「特徴量」というものを使います。モノの写真の角とか辺とかをかき集めて、モノの特徴を拾い出すんですね。コンピューターの目で「特徴量」を拾い出してモノを認識するのであれば、逆に「特徴量」がわからないようにすれば、コンピューターの目にとって、うまく隠れることができるのではないか?ってのが、特徴量を使う発想の元です。既に、手段が目的に代わってしまっていますが(苦笑)、なんか思いついたので試してみたかったのです。

これが背景となる渋谷の画像の特徴量です。いっぱいマルがついていますが、このマルのあるところが、写真の中の特徴的な部分というわけです。約2万点あります。コンピューターの目は(すでに人間の目ではない)、この特徴点を頼りにして、そこに何があるかを調べます。物体の特徴点と比較するわけです。

これが、プロ生ちゃんを置いたときの特徴量の表示です。背景となる部分は変わらなくて…ってことはなくて、FAST で計算したからなのかランダムが入って毎回ちょっと変わるんですよね。うーむ、それはさておき、先の背景だけの特徴量の抽出と、プロ生ちゃんを入れたときの特徴量の抽出を比較して、

  • あまり差がなければ、うまく隠れている。
  • 特徴量の差が大きければ、(コンピュータの目で)見つけやすい

という仮定ができます。

比較をしてみると、

ほら、プロ生ちゃんを置いたときと、置かないときに特徴量の差が、が、が、というストーリーだったのですが、これだと分かりづらいですね。つーか、わかりません…

前後の特徴点の比較は、プロ生ちゃんを置いた場所がわかっているので、その近傍(この場合は、100×100)だけ調べます。透過している背景部分はかわらないはずで、重なっているところの特徴点が違っている状態になる、と予想する訳です。で、その変わっている点が少ない方がうまく隠れている状態で、逆に特徴点がたくさん変わっていると見つかりやすい(隠れていない)と考えることができます。

隠す候補は、回転も含めて 100 点ぐらい用意しておいて、それぞれの特徴量の変化を計算して比較すればよいのです。特徴点のずれ自体は、相関関数を使って計算すればよいでしょう…ってところまでは考えたんですけどね、ちょっとまだ作成中です。

OpenCvSharp を使う

でもって、特徴量を計算したり WPFのImageを扱ったりするのに OpenCV を使っていますが、C# から使える opencvsharp という便利なライブラリがあります。NuGet で取得できるので手軽にプロジェクトに組み込めて便利です。

OpenCV | OpenCV
http://opencv.org/
shimat/opencvsharp
https://github.com/shimat/opencvsharp
NuGet Gallery | OpenCvSharp 2.4.10.20141111
https://www.nuget.org/packages/OpenCvSharp-AnyCPU/

ちなみに、先の特徴量の計算は以下な感じです。OpenCV の中身を弄らないのであれば、CV.Mat でそのまま受け渡しができるので、便利でしょう。実際、カメラキャプチャして画像処理をしているのですが、640×480 程度であれば CVEx.WriteableBitmapConverter.ToWriteableBitmap は 30fps 程度で動きます。

CV.Mat FeatureMatching(
	CV.Mat img1,
	string featureDetectorName,
	string descriptorExtractorName,
	string descriptorMatcherName)
{
	// 特徴点抽出
	var detector = new CV.FastFeatureDetector();
	var keypoint1 = detector.Detect(img1);
	var output = new CV.Mat();
	CV.Cv2.DrawKeypoints( img1, keypoint1, output );

	return output;
}

/// <summary>
/// プロ生ちゃん込みで特徴量を算出
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnClickProNama(object sender, RoutedEventArgs e)
{
	string featureDetectorName = "FAST";
	string descriptorExtractorName = "BRIEF";
	string descriptorMatcherName = "BruteForce";

	// プロ生込みで bitmap に保存
	var path = @"d:temppnpronama.png";
	SaveCanvas(this.cv, path);
	CV.Mat mat1 = new CV.Mat(path);
	var mat = FeatureMatching(mat1, featureDetectorName, descriptorExtractorName, descriptorMatcherName);
	this.img1.Source = CVEx.WriteableBitmapConverter.ToWriteableBitmap(mat);

	this.imgPN.Visibility = System.Windows.Visibility.Hidden;
	this.imgPN2.Visibility = System.Windows.Visibility.Hidden;

}

そんな訳で、非常に中途半端なのですが、ネタ的には(自分的に)面白いので引き続きやります。普通、特徴量の計算は特徴点の抽出は「目立つ」ところを見つけて、物体を検知するのですが、このパターンは逆に「隠れる」ために、特徴量が変わらないようにする、ってのがミソです。まあ、文中にもあるように、あくまで「コンピューターの目」から逃れる手段なので、「人間の目」から逃れられるかどうか疑問だし、たぶん隠れないだろうなーという予想はしているのですが。

カテゴリー: 開発, OpenCV | 1件のコメント

Xamarin + F# の話をいくつか

Xamarin Advent Calendar 2014 – Qiita
http://qiita.com/advent-calendar/2014/xamarin

の8日目の記事です。

まずは Xamarin で F# を使う入り口を

F# は関数型言語だとか、.NET ライブラリがそのまま扱えるとかという話はさておき(そこが利点だったりするわけですが)、まずは Xamarin で F# を使うときの入り口をみていきましょう。

F# Support Overview | Xamarin
http://developer.xamarin.com/guides/cross-platform/fsharp/fsharp_support_overview/

Xamarin のサイトとしては、この1ページしかありません(苦笑)。これ、F# が導入されたころから1ページしかなくて、その後1年経っても1ページしかないんですね。だからといって虐げられているわけではなくて、Xamarin のカンファレンスのビデオを見ると「F# F# F#」連呼していたりする(英語の合間ですが)ので、それなりに重きを置いている言語です。少なくとも VB に対するそっけなさよりも手厚い感じです。

F# 本家のサイトにも Xamarin との連携ページがあって

Use F# for iOS App Development | The F# Software Foundation
http://fsharp.org/use/ios/

こんな風に勉強会のビデオがあります。この解説をしている Rachel Reese さんが発表しているのは、New York City F# User Group なんですが、所属が NYC Mobile .NET Developers Group ってところで、ここのスポンサーに Xamarin と Microsoft が並んでいます。ちなみに Reese さんは、F# MVP  で Xamarin 社とは無関係です(どちらかというと F# 寄りな人)。

このあたりの関係は、以前書いた

Xamarin.iOS/android+F#で作る関数型アプリ
http://www.slideshare.net/moonmile/xamarini-osandroidf

の参考リンクから辿って行けます。

でもって、F# を使って Xamarin.iOS/Android を作る入門編なページを探す訳ですが「ありません」。これは、Xamarin Studio 自体に F# のテンプレートが導入れて間もないのと(1年位しか経ってない?)、ライブラリのあれこれの整合性が大変だったり、そもそも F# を使っているプログラマ人口が少なかったり(あわせて Xamarin を使っている人口もそれなりに少ないだろうし)ってことで、そういうのがありません。
最初のプロジェクト自体は、先の Xamarin のドキュメントにあるように作成できるようにしてあるのですが、その先がなかなか大変です。

F# と Xamarin を同時に学ぶ…ってのは不可能ではないけれども、同時にやるのは大変なので、

  • F# を学んだあとに、ライブラリとして Xamarin に組み込む
  • Xamarin を使いこなした後で、F# に置き直しておく

というアプローチがお勧めです。

どんなところで F# を使うのか?

Xamarin のサンプルも Microsoft のサンプルも C# が一番充実している(というか、唯一になりつつありますが)ので、C# 以外の選択をする場合にはそれなりに理由が要りますよね。Javascript で書くから Cordova、C# で書くから Xamarin、Objective-C/Swift で書くから Xcode みたいなものです。それぞれの利点と欠点を踏まえたうえで(特に欠点を踏まえたうえで)、組み合わせを選択する落とし穴にはまりづらくなります。

端的に言えば、「C# の苦手な部分」あるいは「F# でないと実現できない部分」を見つけて C# と置き換えるのがベターです。

MvvmCross や Xamarin.Forms を使って MVVM パターンを利用すると、自然と View と Logic をライブラリ単位で分けることができます。PCL を使って分けてもよいし、ターゲットが iOS だけなれば、Xamarin.iOS だけ利用するネイティブのライブラリを作ってわけても構いません。PCL にしてしまうと、使えるライブラリが減ってしまったり、DI パターンを利用する必要があったりするので、さくっと作りたいときに不便なので使い分けをします。

この図で行けば、4パターンが考えらます(全体を F# で書く場合も含めると5パターンになるけどそれは別の機会に)。View に F# を使うときは、PCL の Xamarin.Forms を通す場合と、ネイティブの Xamarin.iOS を直接扱う場合。ロジックに含む場合には、ネイティブのデバイス(カメラやGPS)を触る場合と、全く触らずにロジックだけで完結する場合ですね。

F#単独のライブラリを作る

1番導入しやすいのは、ロジックだけで完結する場合ですね。ロジックだけで完結しているので、NUnit が使いやすいし、他のライブラリを使うわけではないのでテストがしやすくなります。このあたりは、普通に C# のライブラリを作るときと変わりませんね。
計算ロジックとかパズルロジックとかを F# で書いて、ユーザーインターフェースを C# で書くパターンがこれです。パズルロジック自体は、NUnit などを使ってテストしたり、別の UI(WPFとか)を使って作れるので便利です。Xamarin との組み合わせではありませんが、F# + OpenCvSharp の画像フィルタをこのパターンで作ったりしています。

特定のデバイスをF#で扱う

特定のデバイスを扱う部分をライブラリ化しますが、これを F# で作るパターンです。この場合、ネイティブのライブラリが C#(内部的には Objecive-C や Java)で提供されているために、あまり F# を使うメリットは無いように見えるのですが…、実はフィルタ絡みとかイベント絡みを書くときに F# は便利です。パイプライン演算子「|>」を使うのと、カリー化をうまく利用すると柔軟にフィルターが作れます。
あとは、デバイスへのアクセスを F# Interactive で動かせるように単独化させておくと、実験などが楽になります。

Viewを扱う部分を F# で書く

moonmile/XFormsPreviewer
https://github.com/moonmile/XFormsPreviewer

では、Xamarin.Forms の XAML を自前でパースしていますが、このようなコードを書くときに F# は便利です。字句解析とクラス生成あたりが素直に書けるのが F# のよいところです。同じコードは C# でも書けるのですが、かなり冗長になります。この場合、ネックだったのが既存のパーサライブラリを使えない(PCL用のパーサがなかった)ってのがあって、F# で自前で書いています。

Xamarin.formsとカスタムコントロールの話
http://www.slideshare.net/moonmile/xamarinforms-41882310

の中にある、カスタムコントロールなところは、F# で書いても十分有効なところです。データバインドとかカスタムセルのところも作りやすいところです。

とはいえ、ハイブリッド特有の落とし穴がある

これは将来的に直るかもしれませんが(One.NETというスタイルで)、現状では、ネイティブアセンブリと、PCL の各種で使えるライブラリが異なるので、ここかかなりネックになります。多くの場合は、DI として Xmarin.Forms の中からネイティブのUIクラスを使うようにインターフェースを切るか、ネイティブそのものでリビルドをしてしまいます。ソースコードが社内や個人持ちであれば、コード共有してリビルドのほうがいいのですが、NuGet などの配布を考えるとクラス設計をして PCL 化しないといけません。ただし、NuGet が絡むと C# でも F# でも事情は同じで、PCL からネイティブのクラスを触るときに問題がでてきます。そのあたりプロジェクト扱いは、次期の Visual Studio 2015 で変わるので、それに次期?Xamarin Studio がどのように対応していくのか、によって F# で作るライブラリの扱いが変わってくるでしょうね。

カテゴリー: 開発, F#, Xamarin | Xamarin + F# の話をいくつか はコメントを受け付けていません

2014年アドベントメモ

何に参加しているかわからなくならないためのメモ

Xamarin Advent Calendar 2014 – Qiita
http://qiita.com/advent-calendar/2014/xamarin

  • 12/8 – Xamarin と F# で
  • 12/22 – Xamarin と AllJoyn で

F# Advent Calendar 2014 – connpass
http://connpass.com/event/9758/?utm_campaign=recent_events&utm_medium=atom&utm_source=feed

  • 12/14 – F# と Fortran で

XAML Advent Calendar 2014 – Qiita
http://qiita.com/advent-calendar/2014/xaml

  • 12/18 – XAML 動的ロードあたり

プロ生ちゃん Advent Calendar 2014 – Qiita
http://qiita.com/advent-calendar/2014/pronama-chan

  • 12/8 – プロ生ちゃん Hidden Object Game あたり

適当に入れたので、12/8 がダブっている…というか、F# のほうは大丈夫だけどプロ生は今週中に何か作らないと。

振り返り

担当分は書き終わったので追記しておきます。文章を書くのが仕事なので、文自体を書くのは苦ではないのですが、さすがにサンプルを作らないと駄目ですよねー、ってのが反省点。あと、何かと数を多めにしてしまったのは敗因です。どっちつかずなのが二つ出来てしまいました。

Xamarin + F# の話をいくつか | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/6729

具体的に F# で PCL を作って、というのが良かったのですが、ざざっと指針を付けておくだけで断念。実は、次世代 One.NET になると PCL の地位が落ちることが分かっている(NuGet からプロジェクト的にライブラリをダウンロード)するので、PCL の制限は撤廃される感じなんですよ。それぞれのネイティブ環境に即したライブラリを NuGet からダウンロードして組み込む、という感じ。なので、F# の各種バージョンの差異と PCL 絡みでタイププロバイダでややこし話は少しは解消されるはずです。PCL の制限を外してしまえば、F# から UI を触るのも苦でなくなるはず。

Xamarin と AllJoyn の将来を考える | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/6778

グローバルサミットで知った AllJoyn ですが、もう少し突っ込んでみたかったものの突っ込むほどライブラリを調べていない状態です。まだまだ日本での認がされてない(企業単位の参画があるので、それなりに認識はされているとは思うのですが)ので、ネットワークで連携をしておくときに既知となるべき情報だと思っています。「既知となるべき」というのは、ある意味で、AllJoyn を使わないという方法も含めるわけで、未知のものではあるけれど知っておいて、やっぱり他の手段(従来の手段)を取るってのもありです。Web API とか Push 通知をするときに手段として知っておくと良いかなと。とはいえ、モバイル機器からリモコン操作したりピアツーピア的に使うときに有効だと思っています。

F# から Fortarn の関数を呼び出そう | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/6759
Let’s call Fortran DLL from F# language. | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/6773

誰が使うんじゃ? F# から Fortran を…ってことを連呼していますが、実は英語圏の F#er な人に(一部)ウケが良くて、リクエストに応じて英文も書きました(ほぼ google 翻訳そのままだったりしますが)。仕事で構造計算を Fortran で書いて、F# で検算する、なんてことをやっている手前、DLL 経由で呼び出せるのだろうか?ってのが去年からの疑問です。と言いますが、このジョークネタは去年思いついてあえなく挫折したものです。ただし、いまだに科学計算の分野(ちょっと前までは OpenCV に Fotran のモジュールが入っていました)では、Fortran が強いので旧来の手続き型を関数型言語から呼び出せるメリットは結構大きいです。あと Intel Fortran はGPU の利用とかパラレル動作とかを有効にしているので、そのあたりも使えると F# には強みになるかも、と思ったり。

XAML は Microsoft だけのモノじゃないので、動的にロードできるよという話 | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/6770

先月、Xamarin.Forms 絡みで XAML を調べていたときにわかったネタです。XAML とは何ぞや?というか、XAML の本質みたいなところですね。UI との組み合わせやデータ記述としての麺が強調されていますが(実用的にはそうなので)、実は、XML とオブジェクト自体のマッピング、プロパティへのバインディングが XAML の主な機能です。とはいえ、マッピング自体が実装依存のなってしまうために、WPF、ストアアプリ、Xamarin.Forms と実装がばらばらになってしまうのが難点です。ここんところ、System.Xaml で共通に扱えればよかったのですが、そこまで抽象化されてなかったのと、WinRT や PCL、Sliverlight あたりの OS 制限により、ばらばらになってしまったのが残念なところです。とはいえ、オブジェクトマッピングとプロパティバインディングだけの実装 XAML を作ってみたいところです。これは後で思考実験をしようかなと。

プロ生ちゃん Hidden Object ゲームを作ろう…の途中 | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/6741

実は、内心一番力を入れたかったところなのですが、大風邪をひいて一番手が抜けてしまいました。いやいや、マスコットアプリもできなかったし、途中で RealSense の到着が挟まっていたりと、あれこれあったのですが、もっと先に作っておくべき代物でした。ただし、私の収穫としては、特徴量って同じ画像でも計算すると抽出結果が異なるんだ、ってことです。静止画だったらまったく同じ結果を得られるのだろう、と思い込んでいたんですよね。このランダム?さは特徴量の計算の手法に依存するのか(内部でランダム値を取り込んでいる)、特徴量抽出自体がランダム値に依存するのか、は後で調べないといけないところです。動画から物体抽出(オブジェクトトラッキング)のために特徴量を使うので毎フレーム異なるのは普通(WEB カメラ自体がノイズを含むので)なので、確率的にオブジェクトを捕えるのですが、静止画の場合はそれが非最適ではあっても一意になっているほうが都合が良いってのはありますよね。もちろん、JPEG圧縮等で含まれるノイズにマッチングする場合もあるのですが、圧縮によるノイズ自体は確定的なわけですから(たぶん、確定的だと思う)。ここを含めて、特徴量を以って、オブジェクト自体を機械の目から隠す、ってのをやってみたいのです。

そんなわけで、あれこれと中途半端になっていますが、ひとまず振り返りということで追記(2014/12/24)。

カテゴリー: 雑談 | 2014年アドベントメモ はコメントを受け付けていません

Xamarin.iOS+MvvmCross を VB で作る

これに「VB でも作れますよ」の返答をしたいだけに、Xamarin.iOS で VB を使ってみました。まあ、正確には、

  • ViewModel を VB の PCL で作る
  • フロントを Xamarin.iOS の C# で作る

訳で、アプリ全体を VB では作ってはいませんが。F# の場合、アプリ全体も作れるので、なんとか工夫すれば VB でも作れると思うのですが、View 部分をコードで書かないといけないし、結構面倒なことになるので、VB+C# のハイブリッド型ということです。Xamarin + Microsoft が C# 押しをしている(ように見えるのは)単一言語で同一の .NET Framework(One.NET)で使えるよ~、という意味で、入り口の取り方としては Java と似ているかなと。多様性という点では、C#/VB/F# と揃っていたほうがいいし、Visual Basic には C# の後追いじゃなくて初心の「初心者にも使える」を押してほしいなと思ったり。この話は別途書くつもり。

フロントエンドは C# のまま

Xamarin.iOS+MvvmCrossでstoryboardを使う方法(MvvmCross v3.2.2 対応) | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/6685

で作ったものを流用します。できれば、プロジェクトの参照設定だけを VB の PCL に変えればいいのですが、最初から作ったのでいくつか嵌りました(汗)。

storyboard ファイルを、C# のプロジェクトからコピーしたものの、Main Interface に設定するのを忘れていて、画面が真っ黒になってあれ?と悩んだり、

Xamarin.iOS が 64bit 化の過渡期なので、MvvmCross が monotouch を要求するので Xamarin.iOS と差し換えたりと。

さっくり 30 分で作って返答するつもりが、夜中に2時間ほどかかっていましたよ。

バックエンドを VB で作る

ViewModel を VB の PCL で作ります。Xamarin Studio では完結しないので、ここでは Visual Studio を使います。まあ、もともと Windows 版の Xamarin Studio では Xamarin.iOS の開発ができないので、Mac 上のものを使うのですが、このあたりは、適当に使い慣れたほうをベースにするのが良いかと。

Namespace ViewModels
    Public Interface ICaluculation
        Function TipAmount(subTotal As Double, generosity As Integer) As Double
    End Interface

    Public Class Calculation
        Implements ICaluculation

        Public Function TipAmount(subTotal As Double, generosity As Integer) As Double Implements ICaluculation.TipAmount
            Return subTotal * CType(generosity, Double) / 100.0
        End Function
    End Class

    Public Class TipViewModel
        Inherits MvxViewModel

        Private _calculation As ICaluculation
        Public Sub New()
            _calculation = New Calculation()
            Start()
        End Sub

        Public Overloads Sub Start()
            _subTotal = 100.0
            _generosity = 10
            Me.Recalcuate()
            MyBase.Start()
        End Sub

        Private _subTotal As Double
        Private _generosity As Integer
        Private _tip As Double

        Public Property SubTotal As Double
            Get
                Return _subTotal
            End Get
            Set(value As Double)
                _subTotal = value
                RaisePropertyChanged(Function() SubTotal)
                Recalcuate()
            End Set
        End Property

        Public Property Generosity As Integer
            Get
                Return _generosity
            End Get
            Set(value As Integer)
                _generosity = value
                RaisePropertyChanged(Function() Generosity)
                Recalcuate()
            End Set
        End Property

        Public Property Tip As Double
            Get
                Return _tip
            End Get
            Set(value As Double)
                _tip = value
                RaisePropertyChanged(Function() Tip)
            End Set
        End Property

        Private Sub Recalcuate()
            Tip = _calculation.TipAmount(SubTotal, Generosity)
        End Sub
    End Class
End Namespace

RaisePropertyChanged メソッドに引き渡すラムダ式の書き方をちょっと悩みますが、Function() SubTotal な感じ書きます。式木になるので、Function() … End Fuction ではダメなのですね。素直にプロパティ名を文字列で書いてもいいかもしれません。

例によって、App クラスの中身は空っぽです。

Public Class App
    Inherits MvxApplication
    Public Sub New()

    End Sub
End Class

実行する

iOS はこんな感じ

Android はこんな感じ

サンプルコード

MxSingleApp 内の MvxVB.* の類がそれです
https://github.com/moonmile/MxSingleApp

カテゴリー: VB, Xamarin | Xamarin.iOS+MvvmCross を VB で作る はコメントを受け付けていません

Xamarin.iOS(storybaord)+MvvmCross+Xamarin.Forms を混在させたアプリを作る

ちょうど Xamarin.iOS のアップデートがあって、Xamarin.iOS10 と monotouch が混乱している状態で苦労したのですが、一応動くところまでできたので記事を書いておきます。

目標

Xamarin.iOS(storyboard) と MvvmCross と Xamarin.Froms を混在させたアプリを作ります。単純に混在させるというよりも、アプリの歴史的な経緯から、

  1. Xamarin.iOS で storyboard で作っているアプリがあって、
  2. 去年あたりに MvvmCross を使って、MVVM 対応したアプリになって、
  3. 今年ぐらいから、Xamarin.Forms に対応したいけどどうしようか?

のようなストーリーを考えています。まあ、MVVM 対応するのは MvvmCross でもよいし、MvvmLight でも Prism でも良いわけですが、そこに Xamarin.Froms の XAML をどうねじ込むか、ってのが問題になりますよね。最初から、Xamarin.Forms で作り直してしまう方法もあるけど労力的に大変だし、そもそも Xamarin.Forms のコントロールは非力なので、そのまま移植できないパターンも多い。DepnencyService とか作ればいいけど、面倒だったら、もともと storyboard と Xamarin.iOS の組み合わせで数ページだけ作るのが簡単ではないか?というパターンです。

アプリの想定

こんな風に、Master-Detail で作っていたアプリに対して、MvvvmCross や Xamarin.Forms のページを追加していきます。

これによって、既存のページはそのままにして、新しいページを MvvmCross や Xamarin.Forms で作れればよいかなと。

プロジェクト構成

storyboard を含むのが、MvxXForms.UI.Touch プロジェクトで Detail ページ用にそれぞれのクラスを設定しています。Mater-Detail の Master がリストの場合は詳細ページは同じページを使うことが多いのですが、Mater が固定ページ(メニューページの代わり)に使っている場合には、項目をクリックしたときにそれぞれの詳細ページが表示されるので、こういう構成にしてあります。Master ページにボタンを並べて画面遷移する場合も似た感じになります。

Xamarin.iOS+storybardのみ場合

最初は、MvxXForms.UI.Touch プロジェクト のようなプロジェクトがあって、まだ MVVM 化されていない状態を考えます。

storyboard は、

– Navigation Controller
– Master ページ
– オレンジ色の Detail ページ

だけの状態になります。Master から Detail へ遷移させる場合は、

Creating an Unwind Segue | Xamarin
http://developer.xamarin.com/recipes/ios/general/storyboard/unwind_segue/

な感じで Ctrl キーを押しながらマウスのドラッグで線が引けます。
サンプルコードでは、RowSelected 内でデータを引き渡すために小細工をしていますが、storyboard segue を使えば画面遷移だけならばノンコーディングでいけます。

MvvmCross のページを追加する

MVVM 化するために、MvxXForms.Core プロジェクトを追加します。ViewModel 自体は、先の MvxXForms.UI.Touch に追加してしまってもよいのですが、先行き Android と共有させることを考えて PCL プロジェクトで作っておきます。

int と string を持つ TipViewModel クラスを定義して、

public class TipViewModel : MvxViewModel
{
	public TipViewModel()
	{
	}

	int _pageNum;
	public int PageNum
	{
		get { return _pageNum; }
		set { _pageNum = value; RaisePropertyChanged(() => PageNum); }
	}
	string _Name;
	public string Name
	{
		get { return _Name; }
		set { _Name = value; RaisePropertyChanged(() => Name); }
	}
}

中身が空っぽな App クラスを作っておきます。App クラスを MvxXForms.UI.Touch プロジェクトから参照しなければよいのですが、まあ、これは初期化のためのお約束コードということで。

public class App : MvxApplication
{
	public App()
	{
	}
}

MvxXForms.UI.Touch プロジェクトに戻って、UIApplicationDelegate を MvxApplicationDelegate に変更。
FinishedLaunching メソッドをオーバーライドして、MvvmCross の初期化を行います。

public partial class AppDelegate : MvxApplicationDelegate
{
	// class-level declarations

	public override UIWindow Window
	{
		get;
		set;
	}

	public override bool FinishedLaunching(UIApplication app, NSDictionary options)
	{
		var presenter = new MvxTouchViewPresenter(this, Window);
		var setup = new Setup(this, presenter);
		setup.Initialize();
		return true;
	}
}

あとは、Detail ページに対応する ViewController を MvxViewController から継承させて、set.Bind 等でバインドを行えば ok です。

public partial class Detail2ViewController : MvxViewController
{
	public Detail2ViewController(IntPtr handle)
		: base(handle)
	{
	}

	public new TipViewModel ViewModel
	{
		get { return (TipViewModel)base.ViewModel; }
		set { base.ViewModel = value; }
	}

	public override void DidReceiveMemoryWarning()
	{
		// Releases the view if it doesn't have a superview.
		base.DidReceiveMemoryWarning();

		// Release any cached data, images, etc that aren't in use.
	}

	public override void ViewDidLoad()
	{
		this.Request = new MvxViewModelRequest(typeof(TipViewModel), null, null, new MvxRequestedBy());
		base.ViewDidLoad();
		// Perform any additional setup after loading the view, typically from a nib.
		var set = this.CreateBindingSet<Detail2ViewController, TipViewModel>();
		set.Bind(labelPageNum).To(vm => vm.PageNum);
		set.Bind(labelName).To(vm => vm.Name);
		set.Apply();

		// マスターからのデータ引き渡し
		this.ViewModel = MasterViewController._datavm;
	}
}

storyboard の Detail ページと Detail2ViewController の結び付けは、プロパティウィンドウで Class を変更します。このあたりは Xcode と同じですね。

MasterViewController._datavm なところは、storyboard segue を使うと、内部的に一気に ViewController が作られてまうので、ViewModel プロパティを設定するタイミングがないため、こうやっています。Master ページで Cell をクリックしたときに、下記な方法でグローバル変数で渡します。ちょっとダサいんですが、仕方がありません。

public override void RowSelected(UITableView tableView, NSIndexPath indexPath)
{
	var data = new MyData();
	switch ( indexPath.Row )
	{
...
		case 1:
			/// MvvmCross を使って vm 経由でデータを渡す
			/// 本来は data 経由のほうがいいけど、これはサンプルで
			/// あらかじめ storyboard segue でつなげておく
			_datavm = new TipViewModel()
			{
				PageNum = 2,
				Name = "use MvvmCross"
			};
			break;
...
}

storyboard segue を使わずに画面遷移をする

じゃあ、明示的に遷移先の ViewController を作って ViewModel を設定する方法でもよいだろう、というのが次の方法です。
目的の ViewController の「storyboard id」に、あらかじめ「Detail3ViewController」という名前を付けておいて(これはクラス名と異なっていても構いません)、Storyboard.InstantiateViewController メソッドで作成します。これを、NavigationController.ShowViewController メソッドで表示すれば ok です。

/// <summary>
/// 行をクリックしたとき
/// </summary>
/// <param name="tableView"></param>
/// <param name="indexPath"></param>
public override void RowSelected(UITableView tableView, NSIndexPath indexPath)
{
	var data = new MyData();
	switch ( indexPath.Row )
	{
...
		case 2:
            /// storyboard のページを直接開く
			/// Storyboard ID を ViewController に設定しておく
			/// storyboard segue を使わないパターン
			var vc = (Detail3ViewController)Storyboard.InstantiateViewController("Detail3ViewController");
			this.NavigationController.ShowViewController(vc, this);
			_datavm2 = new TipViewModel2()
			{
				PageNum = 3,
				Name = "Mvx + direct storyboard"
			};
			break;

遷移先の ViewController を MvxViewController を継承するようにして、ViewModel に対応させてもそのまま使えます。
ちょっと注意しなければいけないのは、MvvmCross では ViewModel と ViewController が 1対1 じゃないと駄目なようです。実行時に TipViewModel が二つ以上の ViewController に設定されている、とエラーがでます。なので、仕方がないので TipViewModel2 という同じ中身のクラス(継承しているだけ)を使っているのですが。同じ ViewModel を複数の View に対応しても良いと思うのですが、ちょっとこの動きはよくわかりません。

Xamrin.Forms のページを呼び出す

Xamarin.Forms の XAML ページを Master ページから呼び出せるようにします。
MvxXForms.Form プロジェクトを別に作っていますが、たぶん、MvxXForms.UI.Touch に含ませてしまっても大丈夫だと思います。

DetailXFPage.xaml の中身を手書きします(Xamarin Studio を使うと、少しだけコード補完が効いて楽です)。

<?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="MvxXForms.Form.DetailXFPage"
					   Title="xamarin.forms page"
					   BackgroundColor="Yellow"
					   >
  <StackLayout Padding="10,80,10,10">
    <Label x:Name="label1" Text="Xamarin.Forms page"  />
    <Label Text="PageNum" />
    <Label Text="{Binding PageNum, StringFormat='{0}'}" BackgroundColor="Lime" />
    <Label Text="Name" />
    <Label Text="{Binding Name}"  BackgroundColor="Lime"/>
  </StackLayout>
</ContentPage>

Binding が XAML の中に記述できます。

Xamarin.Forms のプロジェクトでも App クラスがあるのですが、これは GetMainPage メソッドのように PCL プロジェクト内で作成した Page オブジェクトを返すための static メソッドです。なので、同じように、DetailXFPage を new して返すだけのメソッドを作っておきます。

public class App
{
	public static Page GetDetailPage()
	{
		return new DetailXFPage();
	}
}

Xamarin.Forms のページを呼び出すときは、先の storyboard segue を使わない方法と同じように、NavigationController.ShowViewController メソッドを使います。

public override void RowSelected(UITableView tableView, NSIndexPath indexPath)
{
	var data = new MyData();
	switch ( indexPath.Row )
	{
...
		case 3:
			// Xamarin.Forms ページを開く
			var page = MvxXForms.Form.App.GetDetailPage();
			var vc2 = page.CreateViewController();
			var vm = new TipViewModel()
			{
				PageNum = 4,
				Name = "xamarin froms page"
			};
			page.BindingContext = vm;
			this.NavigationController.ShowViewController(vc2, this);
			break;

ContentPage の BindingContext プロパティに ViewModel のデータを設定すればバインドが完了します。

Xamarin.Forms の初期化のために、AppDelegate クラスに Forms.Init() を追加しておきます。
これで、Xamarin.Forms と MvvmCross が混在できます。

public partial class AppDelegate : MvxApplicationDelegate
{
	// class-level declarations

	public override UIWindow Window
	{
		get;
		set;
	}

	public override bool FinishedLaunching(UIApplication app, NSDictionary options)
	{
		Forms.Init();
		var presenter = new MvxTouchViewPresenter(this, Window);
		var setup = new Setup(this, presenter);
		setup.Initialize();
		return true;
	}
}

実行してみる

こんな風に、Master のページから各種のページに遷移ができます。

サンプルコード

MxSingleApp の中の MixMvxForms
https://github.com/moonmile/MxSingleApp

参考先

Xamarin.iOS ナビゲーションコントローラ – SIN@SAPPOROWORKSの覚書
http://furuya02.hatenablog.com/entry/2014/07/03/035352
Xamarin.iOSでStoryboardとXamarin.Formsを併用するには? – Build Insider
http://www.buildinsider.net/mobile/xamarintips/0006

カテゴリー: C#, Xamarin, iOS | Xamarin.iOS(storybaord)+MvvmCross+Xamarin.Forms を混在させたアプリを作る はコメントを受け付けていません

C# の Dictionary と F# の map

ちょっと気になったのでメモ書き

C# の Dictonary は referencesource/mscorlib/system/collections/generic/dictionary.cs にあって、buckets[hashCode % buckets.Length] な形でハッシュ値で計算。

F# の map は fsharp/src/fsharp/FSharp.Core/map.fs にあって、comparer を使って二分木

ちなみに C# の SortedDictionary は referencesource/System/compmod/system/collections/generic/sorteddictionary.cs にあって、TreeSet<KeyValuePair<TKey, TValue>> な二分木で計算。

ReadOnlyDictonary ってのもある。 ここ にソースがあるので見ると、dictonary を渡しているだけなので、中身は一緒。追加用のメソッドがないだけ。同じように ReadOnlyCollection があるけど、内部的には IList と同じ。なので、非同期に特化しているとか、分散されているとか、という訳ではないらしい。逆に言えば、初期化するときに分散に特化させたリストを渡せば、表面上は ReadOnlyCollection として扱える。Add メソッドなどを呼び出すと、実行時にエラーが発生する(メソッド自体をなくしてしまって、コンパイル時にエラーにする、ってのでもいいかもしれない)。

 

 

カテゴリー: 開発 | C# の Dictionary と F# の map はコメントを受け付けていません

Xamarin.iOS+MvvmCrossでstoryboardを使う方法(MvvmCross v3.2.2 対応)

Xamarin.iOS+MvvmCrossでstoryboardを使う方法 | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/5814

以前、書いたのですが、バージョンが上がって微妙に動きが異なっているので、メモ書きしておきます。
サンプルコードは http://1drv.ms/1CeHWYp からダウンロードができます。

MvvmCross のサンプルコードを storyboard 対応にする

Tip Calc The Core Project
https://github.com/MvvmCross/MvvmCross/wiki/Tip-Calc—The-Core-Project
Tip Calc A Xamarin.iOS UI project ・ MvvmCross/MvvmCross Wiki
https://github.com/MvvmCross/MvvmCross/wiki/Tip-Calc-A-Xamarin.iOS-UI-project

TipCalc.Core の中身

ViewModel は MvxViewModel クラスを継承して作ります。ここのバインドは、INotiryPropertyChanged を実装していればよいので、何で作っても良いはずです。
プロパティの変更時に、RaisePropertyChanged で変更通知をします。

public class TipViewModel : MvxViewModel
{
	private readonly ICalculation _calculation;
	public TipViewModel(ICalculation calculation)
	{
		_calculation = calculation;
	}

	public override void Start()
	{
		_subTotal = 100;
		_generosity = 10;
		Recalcuate();
		base.Start();
	}

	private double _subTotal;

	public double SubTotal
	{
		get { return _subTotal; }
		set { _subTotal = value; RaisePropertyChanged(() => SubTotal); Recalcuate(); }
	}

App.cs の中身は、空っぽでも動きます…と思ったけど、Calculation のインスタンスだけ作らないとダメです。この部分は、Calc 部分を ICalc で作っているので、こうなっているので、特に作らなければ App() の中身は空でも大丈夫です。

public App()
{
	Mvx.RegisterType<ICalculation, Calculation>();
	// Mvx.RegisterSingleton<IMvxAppStart>(new MvxAppStart<TipViewModel>());
}

RegisterSingleton を使うとシングルトンで作られてしまい、都合が悪いことが多いので、UI プロジェクトのほうで作ります。

TipCalc.UI.Touch の中身

Setup.cs の中身はほとんど空っぽです。

public class Setup : MvxTouchSetup
{
	public Setup(MvxApplicationDelegate appDelegate, IMvxTouchViewPresenter presenter)
		: base(appDelegate, presenter)
	{
	}

	protected override Cirrious.MvvmCross.ViewModels.IMvxApplication CreateApp()
	{
		return new App();
	}
}

AppDelegate.cs の中身は、Window プロパティを残して、FinishedLaunching だけオーバーライドします。
内部で window を作っているサンプルコードもあるのですが、別のところから Window プロパティを参照することができるので、元の状態で残したほうがベターです。
以前と違って、Setup の引数が変わっているので、MvxTouchViewPresenter オブジェクトを作って引き渡します。
まあ、Setup 自体を変えてしまってもいいのですが。

 [Register("AppDelegate")]
public partial class AppDelegate : MvxApplicationDelegate
{
	// class-level declarations
	public override UIWindow Window
	{
		get;
		set;
	}

	public override bool FinishedLaunching(UIApplication app, NSDictionary options)
	{
		var presenter = new MvxTouchViewPresenter(this, Window);
		var setup = new Setup(this, presenter);
		setup.Initialize();
		return true;
	}
}

TipCalc.UI.TouchViewController.cs の ViewModel は、MvxViewController を継承するように変更して、ViewDidLoad メソッドの中身だけ変更します。
base.ViewDidLoad で元のメソッドを呼び出す前に、MvxViewModelRequest オブジェクトを作らないといけません。この引数が変更になっていて、ViewModel のクラス名(ここでは TipViewModel )を渡します。

CreateBindingSet は拡張メソッドなので、
using Cirrious.MvvmCross.Binding.BindingContext;
することを忘れずに…いつもあれ?ってなるので。

public partial class TipCalcUITouchViewController : MvxViewController
{
	public TipCalcUITouchViewController(IntPtr handle)
		: base(handle)
	{
	}

	public new TipViewModel ViewModel
	{
		get { return (TipViewModel)base.ViewModel; }
		set { base.ViewModel = value; }
	}

	public override void ViewDidLoad()
	{
		this.Request = new MvxViewModelRequest(typeof(TipViewModel), null, null, new MvxRequestedBy());
		base.ViewDidLoad();
		// Perform any additional setup after loading the view, typically from a nib.
		var set = this.CreateBindingSet<TipCalcUITouchViewController, TipViewModel>();
		set.Bind(labelTip).To(vm => vm.Tip);
		set.Bind(textSubTotal).To(vm => vm.SubTotal);
		set.Bind(sliderGene).To(vm => vm.Generosity);
		set.Apply();
	}
}

Bind でコントロールを指定して、To で ViewModel のプロパティと結びつけます。いわゆる Binding の Path は .For( c => c.Text) で明示的に指定もできますが省略可能です(デフォルトプロパティを内部で持っていると思われる)。

実行結果

こんな風にスライダーを動かすと、ラベルの数値が変化します。

20141126_02

サンプルコード

サンプルはこちら
http://1drv.ms/1CeHWYp

カテゴリー: Xamarin, iOS | Xamarin.iOS+MvvmCrossでstoryboardを使う方法(MvvmCross v3.2.2 対応) はコメントを受け付けていません

Xamarin.Forms の話ともうちょっと突っ込んだ話…のメモ書き

第2回 Japan Xamarin User Group Conference 東日本編 : ATND
https://atnd.org/events/57246/

で 50分ほど頂いたので、Xamarin.Forms の概要ともうちょっと突っ込んだ話をします。

当日、聴衆の様子を見てから判断しますが、Xamarin.Forms の概要は、概要は Xamarin のホームページにあるし、日本語の情報もちらちらと揃っているので「概要」だけ聞かされても面白くない、って方が多い(私もその一人)と思われるので、

  • Xamarin.Forms のざっと概要を 15 分程度
  • カスタムコントロールを作る話を残りの時間で

ってことを考えます。カスタムコントロールは、いくつか方法があって、その中で 3 つの方法を紹介します。

  • 既存のコントロールを継承して、Xamarin.Forms 内で完結する方法
  • ネイティブ環境(iOS/Android)を使うために DependencyService を使う方法
  • カスタムレンダラーを使って、ネイティブ環境(iOS/Android)で描画させる方法

これも、それぞれについては Xamarin サイトや日本語の解説ページがあるのですが、ひとまとめに書いているものが無いのと、それぞれのサンプルが実用的すぎて難しい(!)ので、簡単なサンプルで比較します。

それぞれの解説自体は、本家 Xamarin のドキュメント(英語だけど)に載っている。

日本語のサンプルもある。

この他に考えられるカスタムコントロールとしては、

  • Xamarin.Forms.Labs を使う(ライブラリを買うとパターン)
  • リフレクションを使う(DependencyService と同じだが、インターフェースを定義しない)

ぐらいでしょうか。Xamarin.Forms 用のコントロールもいくつかあるので、それを購入するという方法もある。

話の流れ

  • Xamarin.iOS, Xamarin.Android で、ネイティブな環境のアプリを C#(.NET)で作れる。
  • UIが別(storyboard, axml)だったので、共通で使える Xamarin.Forms が現れる。
  • Xamarin.Forms のベースは XAML になる。
    • XAML の規格は Microsoft が公開していて、自由に作れる。
    • x:Class, x:Name などが決められている。
    • Microsoft の WPF/Sliverlight などの XAML と互換ではないが…いくつか互換がある。
    • iOS, Android, Windows Phone(Silverlight) の共通のコントロールが用意されている。
    • データバインドが使える。MS-XAML に規定されている {Binding …}
    • ドット付の名前 Grid.Row などが使える。これも MS-XAML に規定されている。
    • PLC あるは Shared プロジェクトとして作り、UI を共有する。
  • ベースコンテナで ContentPage などがある。
    • Grid、StackLayout のように MS-XAML と互換がある。
  • Xa-XAML は、XAML を解釈したのちに、それぞれの環境のコントロールにレンダリングする。
    • MS-XAML は、直接オブジェクトに変換される、という違いがある。
    • これは WPF, Silverlight, WinStore-XAML, WP-Xaml とそれぞれ違う
  • が、表面上は一緒なので、Xamarin.Forms も MS-XAML と同様に扱える。
  • 大抵は StackLayout と Grid を使いこなすと良い。
  • それぞれのプラットフォームの最大公約数なので、プラットフォーム特有の機能がない。
    • タップイベントやドラッグがないのが辛いところ。
  • 独自のコントロールや、機種ごとの機能を使うことができる。
    • 独自コントロールは、MS-XAML のユーザコントロールと似たように、既存のコントロールを組み合わせられる
      • ContentPage を継承した例が多いが、View を継承しても作ることができる。
      • xmlns:local=”clr-namespace=…” を使って、独自アセンブリをロードする
      • <local:CustomButton…> のように書く。
        • が、StackLayout の最後に計算されるという Bug ? がある。
    • DependencyService を使って、プラットフォーム毎の機能を使う。
      • 要するに intarface を利用した委譲パターン(Listenパターン?)
      • インターフェースを PCL 側に定義する
      • 内部動作を iOS/Android 側で実装する。
        • [assembly: Dependency … ] を定義する
      • DependencyService.Get<…> で呼び出す。
        • 実装がないときは null になる(コードを変えなくて良い利点がある)。
      • このテクニックは、共通処理を PCL で書き、それぞれの動作をプラットフォーム毎に書くパターンと同じなので、UI だけでなく普通の処理にも使える(機種番号を拾うとか、独自のフォルダアクセスとか)
    • カスタムレンダラを使う
      • 独自コントロールの内部動作だけ、プラットフォームに依存させる。
      • PCL に既存コントロールを継承したクラスを作る。
      • 実行時のレンダリングを、iOS/Android で OnElementChanged として書く。
        • たとえば Entry コントロールの場合は、レンダリング用の  EntryRenderer が定義されている。
        • ASP.NET のユーザコントロールの作り方に似ている。
        • ネイティブコントロール(iOS/Android)を自由に扱える。
  • 使い分ける
    • 共通画面や共通部品は、Xamarin.Forms の基本コントロールをまとめて扱う。
      • 独自のプロパティを作って、データバインディングすると再利用性が高まる。
      • XAML, コードのコピペではなく、ライブラリとして提供できる。
    • DependencyService は、ピンポイントで機種依存の機能を使う。
      • 共通のインターフェースを必要とするが、自分で定義できる。
      • PLC 内では Device で分岐させることも可能
        • ただし、iOS, Android, WP Silverlight 限定になるが… Device クラスを独自に作ることも可能。
    • UI がある場合は、カスタムレンダラを使う。
      • 応用範囲が広い
      • 必ず、Xamarin.Forms のコントロールを継承する必要あり? Renderer なので。
      • OnElementChanged 内で、マウスイベントを取ることも可能?
        • グラフィック表示
        • マウスイベントの取得
        • アニメーション処理
      • 機種ごとに、Xamarin.iOS/Android が使える。

これに図を加える。

カテゴリー: Xamarin | Xamarin.Forms の話ともうちょっと突っ込んだ話…のメモ書き はコメントを受け付けていません