日本語版Visual Studio 2013 に Xamarin 4.2.3 が入らない場合の対処

Visual Studio 2012 と Visual Studio 2013 が同じPCに入っていると、何故か Xamarin Shell が 2012 のほうにしかインストールされなくて、肝心の 2013 では動作しないというインストーラのバグっぽい動きの回避方法です。半日ほど嵌ったので。
※以前のインストーラーは VS2010, VS2012, VS2013 を別々に判断していたのですが、4.2.3 のインストーラから同時に入れるようになっています。選択肢がなくなっているので、たぶんインストーラのバグかと。

image

Visual Studio 2013 の「拡張機能と更新プログラム」を確認すると、何故か Xamarin Shell が入っていませんでした。何度再インストールしてもダメなのですが、どうせ拡張機能なのだから VS2012 と互換ではないかと思って、コピーすることに。

Install Xamarin in VS 2013 Preview 1 – fd Blog と同じように、VS2012 のフォルダーからコピーをします。実質必要なのは、c:\Program Files (x86)\Microsoft Visual Studio \12.0\Common7\IDE\Extensions\Xamarin だけなので、これを「管理者モード」でコピー。

そのあとに、”c:\Program Files (x86)\Microsoft Visual Studio \12.0\Common7\IDE\devenv.exe” /setup /nosetupvstemplates を管理者モードで実行します。「コマンドプロンプト(管理者)」を使えばOK。何もメッセージはでませんが、設定がリセットされています。

念のためキャッシュである、C:\Users\masuda\AppData\Local\Microsoft\VisualStudio\12.0\Extensions と C:\Users\masuda\AppData\Local\Microsoft\VisualStudio\12.0\ComponentModelCache も丸ごと削除しておきます。これは Visual Studio 2013 を起動したときに自動的に作られるので大丈夫です。

ひとまず、2日間ほど動かした感じでは、日本語環境で XAML(ストアアプリのデザイナ)が開けなる現象は発生していません。ようやく、日本語の Visual Studio 2013 で Xamarin を使って開発ができるという環境が整った感じです。

お次は、Android のシミュレーターが遅いので、BlueStacks を使えないかどうかをチェックしている途中です。Titanium + BlueStacksでAndroid開発 | Selfkleptomaniac を見る限り、アプリのインストールはできそうなのですが、私の環境では落ちるんですよね。Android のバージョンが違うのかな?

カテゴリー: Xamarin | 日本語版Visual Studio 2013 に Xamarin 4.2.3 が入らない場合の対処 はコメントを受け付けていません

ActivePerl に DBD::mysql をインストールする方法

Unix 版は簡単なんだけど、どうも Windows のほうは cpan ではうまくインストールできなかった(make test あたりでこける)ので、ppm を使えってことで。

私の環境では 64bit 版の ActivePerl is Perl for Windows, Mac, Linux, AIX, HP-UX & Solaris | ActiveState が c:Perl64 に入ってます。

1. コマンドラインから ppm を起動

image

2. Perl Package Manager が起動するので、上の検索に「dbd-mysql」と入力。

image

3.検索が絞られるので、左上の mark for install でチェックした後「→」ボタンの run mark action でインストール

image

正常にインストールできたら、c:Perl64sitelibDBD の中に mysql.pm があることを確認。

image

■実行テスト

se DBI ;
$db = DBI->connect('DBI:mysql:database','user','pass');
$rows = $db->selectall_arrayref("SELECT id, name, tel, modified from store;");
@row = @$rows ;        # 一度、配列に直す
$cnt = @row ;        # 行数を取得
print "count: $cntn" ;
# 繰り返し処理
foreach $r ( @row ) {
    print "num: $r->[0] $r->[1]n" ;
}

# 直接参照するとき
# print $rows->[0][3] ;

fetch で回してもよいのだが、selectall_arrayref で一気に配列に取り込んだほうが楽かもしれない。
日本語は「????」になってしまうので、これをどうするかは不明。datetime 型もどうやって取るかわからず。

追記
UTF8にするには、
$db = DBI->connect(‘DBI:mysql:db’,’user’,’pass’,{‘mysql_enable_utf8’=>1});
で良い模様。

カテゴリー: 開発, Perl | ActivePerl に DBD::mysql をインストールする方法 はコメントを受け付けていません

Xamarin から WiFi経由で Android を動かす

昨日の続きですが、AndroidのWiFiデバッグ – 滴了庵日録 を参考にすると、あっさり動きました。

一応、手順を示しておくと、

  1. Android を USB 接続する。
  2. adb devices でデバイスが認識できる状態にしておく。
  3. adb tcpip 5556 で、Android のサーバーをポート番号 5556 で起動する。ここのポート番号は自由に設定してOK。
  4. adb connect 172.16.0.9 のように、Android に接続する。IP は Android の IP アドレス。
  5. USB ケーブルを抜く。
  6. adb devices を起動して、デバイスが tcpip 経由でつながっていることを確認する。

List of devices attached
172.16.0.9:5556 device

な感じで接続が確認できます。

tcp/ip 接続を切るのは adb disconnect 172.16.0.9 なんだけど、Android 側のサーバーが kill されるかどうかは不明です。

■嵌るところ

で、いろいろ検索すると落とし穴ったぽいのが、「adb connect 172.16.0.9:5555」のようにポート指定しているものが多いけど、実際は「adb connect 172.16.0.9」です。たぶん、Linux の adb がそうなのか、それとも古いだけなのか。Windows 版の最新の adb だと IPアドレス/ホスト名だけを指定します。

ポート番号が 5555 を指定しているので、皆 5555 を使ってしまうけど、うっかり公共無線LAN 上で IP アドレス知れたらポート番号固定でアタックが掛けられる(やっている人はいる?)ので、いまどきならばポート番号は変えたほうがベターかと。

ひとまず、VMWare から Android に USB 接続しようとすると最初の接続が不安定(何故かホストPCのUSBポートを1つしか認識しないんですよね…)なので、無線LAN接続できるようにしておくと便利です。自宅とか会社でやる分にはOKかと。

カテゴリー: Xamarin | Xamarin から WiFi経由で Android を動かす はコメントを受け付けていません

Xamarin から Android の実機を動かす

Androidのシミュレータが遅いので実機を使います…っていうんですが、なかなかしんどいので手順を残しておきます。

■実機を用意する

手元に実機がないので、何でもいいのですが タブレット Diginnos Tablet DG-D07S|ドスパラ公式通販サイト を買いました。Andoroid ver.4.2だそうだから、程よく新しくてまあ中華パッドだけどよいかという感じで。ちなみにこのタブレットは Google Play が入っていません。後から入れることも可能らしいので買ったのですが、また実験しておりません。まあ、しばらくはデバック機として過ごす予定です(今はビデオが流れていますが)。

■VMWare上に Xamarin Studio と Visual Studio を用意する

XamarinからiOSシミュレータを起動する | Moonmile Solutions Blog の環境として、VMWare 8 上に英語版 Windows 8.1 を入れておきます。結論から言うと、Win8.1 をホストにして VMWare 8(最新は 10)+ Win8.1 で Android 実機につなげられます。

■Android の ADB用USBドライバーをインストール

Android SDK Manager を起動して「Google USB Driver」をインストールします。Visual Studio の上にあるアイコンをクリックするか、C:Users<ユーザー名>AppDataLocalAndroidandroid-sdk のフォルダの「SDK Manager」を開きます。

image

下のほうにある Extras フォルダの「Google USB Driver」をチェックしてインストール。

image

■実機のドライバーをインストールする

Windows 8でAndroidのADB用USBドライバーをインストールする方法 とか Google USB DriverでAndroid端末をWindowsに認識させる – Yahoo!知恵袋 とかを参考にしてドライバをインストールします。

  • 大抵の場合 android_winusb.inf ファイルを修正して %SingleAdbInterface% と %CompositeAdbInterface% を追加する。ベンダー ID を指定しないとインストールできない模様。

DG-D07S の場合は、

;DG-D07S
%SingleAdbInterface% = USB_Install, USB\VID_2207&PID_0010
%CompositeAdbInterface% = USB_Install, USB\VID_2207&PID_0010&MI_01

を [Google.NTx86] と [Google.NTamd64] の両方に追加します。

  • google の usb ドライバーには署名が入っていないので、bcdedit /set testsigning on を実行してテストモードでインストール。元に戻す時は bcdedit /set testsigning off にする。

単に署名のないドライバーをインストールするだけなので「安全」です。もちろん、Googleを信用するってのが前提ですが。

■実機のUSBデバッグを有効にする

Windows に Xamarin.Android をインストール : XLsoft エクセルソフト のように、実機の「USBデバッグ」を有効にします。機種によって違うのですが「アプリ開発者用」とかのカテゴリにあります。

■VMWare上から実機へ接続する

うまく認識すると、下のように「Android Composite ADB Interface」が表示されます。VMWare上でこれが出ないときは、

image

「取り外し可能デバイス」のところで Android の実機を切り離してやります。何かタイミング(順序?)があるらしく、「ホストから切断」(VMWareに接続)した状態で、何回かUSBを抜き差しすると認識します。USB認識があるので、抜き差しの間に10秒ぐらい置くとうまくいきます。

同じUSBポートにハブでつなぐとうまくいくけど、別のUSBポートだとダメな感じですね。VMWare 10 だとうまく動くのかもしれません。

→ VMWare Workstation 10 にバージョンアップをすると、確実につながるようになりました。10 から USB が 3 ポートサポートされているので、おそらく 8 の場合は1つだけだったのかも(USB接続のキーボードとマウスとの競合っぽい)。となると、最新の VMWare Player 6 でもうまくいくかも。

image

■ADO devices で確認する

必須かどうか不明なのですが USB接続でadbコマンドを使う – forzando@net を参考にして、

  • adb start-server サーバーを起動
  • adb kill-server サーバーを止める
  • adb debices 接続デバイスの一覧を表示

ここにデバイスマネージャで表示されている実機が出てこない場合は、何か adb.exe がおかしいパターンが多いです。

私の場合、 DG-D07SのADB認識について | AndroidのQ&A【OKWave】 と同じ現象で、google のではなく、配布されている adb.exe と *.dll を差し替える(C:UsersmasudaAppDataLocalAndroidandroid-sdkplatform-tools にコピーする)とうまく動きました。

adb devices でデバイス表示をさせると、自動的にサーバーが起動します。

■Xamarin Studio から実機へ起動させる

プロジェクトの「Run With」(日本語だと何?)から実機を選択します。「Mono Soft Debugger for Android」のはシミュレータですね。Windows に Xamarin.Android をインストール : XLsoft エクセルソフト のように、Genymotion Emulator を使ってもよいのですが、私のPCは Intel VTを動かせない(VMWareと競合する)ので試していません。

実機の接続を切ってしまうと、ここのリストに出てこないので、Xamarin Studio を再起動させます。

image

■Visual Studio から実機を動かす

ツールバーにターゲットが表示されます。「rockchip DG-D075」というのが実機です。これも USB を抜いてしまうと実機を認識しないので、Visual Studio を再起動します。

image

というわけで、VMWare 上の Xamarin から実機へのデバッグ実行ができました。実機の画面キャプチャがないのは、私が「実機の画面キャプチャの方法を知らない」からです(苦笑)。だって、Andoroidを触ってまだ1日目ですから。

そうそう、実機へのデプロイ時に Android のバージョンが異なるとエラーになるので、当然ですがそろえておきます。

Set Up Device for Development | Xamarin を見ていくと WiFi 経由でデバッグ実行ができるみたいなんですよね。USB ケーブルの場合、VMWare の認識でややこしいので無線LAN経由でやりたいところです。この設定はあとから試してみます。SmartQ 5 – アプリケーション開発とデバッグ | Scenery and Fish とか、Wifi接続でadbコマンドを使う – forzando@net があるので。

カテゴリー: Xamarin | 1件のコメント

XamarinからiOSシミュレータを起動する

MvvmCross と Xamarin for Visual Studio で iOS, Android, Windows アプリを作る流れ – Yuta Watanabe’s Blog を参考にして、手始めに iOS とストアアプリの共通ロジック(PCL)を試そうかと思ったので嵌ったのでメモ。MVP Community Camp 2014 の発表用の下ごしらえというのもあるのですが、その他もろもろ。

■Xamarin.com からダウンロードして Windows/Mac に入れる

http://xamarin.com/download からガンガンダウンロードしてインストールします。Visual Studio 2013 にアドインを入れると Windows ストアアプリの XAML が開けなくなる…ってのは直ったかどうかわからないので、別途英語版のWindows8.1 を作ってインストールしてます。

iOS 用のアプリを C# で作る訳ですから、Windows のほうには

  • Xamarin.iOS
  • Xamarin Studio
  • Visual Studio integration

Mac のほうには、

  • Xamarin.iOS
  • Xamarin Studio
  • Xamarin.Mac

を入れます。

■Xamarin Studio のバージョンを揃える

Windows と Mac のバージョンを揃えます。最初 Mac のほうでペアリング用の「Xamarin.iOS Build Host」が見つからなくて困ったのですが、xamain.com から直接ダウンロードできるのは 4.0.2 で、Mac 使って iOS シミュレータを動かせるのは、4.2.2 です。ここで嵌って @ytabuchi さんに聞きました。

image

Visual Studio の場合は、オプションの「Xamarin」→「iOS Settings」でアップデートができます。

image

■ペアリングを設定する

Visual Studio から Mac の iOSシミュレーターを動かす場合は、Mac 側で「Xamarin.iOS Host Build」を起動します。Xamain のアップデートをした後に PC を再起動してなかったので、このあたりかなり嵌ったんですよね。PC と Mac の両方を再起動することでうまく動くようになりました。

image

同じ PIN コードを Visual Studio 2013 のほうでも打てば OK

無事接続ができれば、Visual Studio 2013 から Mac 上の iOS シミュレータが起動します。ターゲットで ios シミュレーターを選択することを忘れずに。

image

ちなみに、ペアリングは Visual Studio 単位らしく、複数の VS2013 を立ち上げるとペアリングがうまくいきません。ペアリングが取り合いになってしまうようです。接続先がオプションの中に書いてあるので仕方がないのですが、複数のプロジェクトを同時にひらいて切り替えて使いたいときはちょっと不便です。

カテゴリー: 開発, Xamarin | XamarinからiOSシミュレータを起動する はコメントを受け付けていません

CakePHPのXMLレスポンスをListViewで一覧表示する

CakePHPのXMLレスポンスをストアアプリで一覧表示する | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/5374

の ListView 版です。GridView の場合、横スクロールなのですが、ListView は縦スクロール。WPF の ListView と同じ感じ…では使えないので結構面倒です。なので、フォームにあるリストビューを作りたい場合は下手に自作するよりもコンポーネントを買ったほうがいいような気がするのですが。Windows UI http://jp.infragistics.com/products/windows-UI.aspx のグリッドコントロールじゃないですかね。

が、あえて自作します。

こんな風にフォームアプリのように縦スクロール。右側にそれぞれの値を表示という画面です。
まず、標準で「これじゃない感」が強いので、このままでは役に立たないのです。これじゃないところを列挙すると、

  • 縦スクロールすると、タイトル部分もスクロールしてしまう。
  • 幅をユーザーが自由に変えられない。

ちなみに、業務のほうは、ヘッダ部分を ListView の外側に追いやって逃れました。ヘッダクリックでのソートと幅の変更は WPF の ListView には備わっているのですが、WinRT のほうにはありません。というか、まったく別物です。

データモデルは同じなので、リストビューを作るところから。

■リストビューを作る

<ListView 
    ItemsSource="{Binding Items}"
    d:DataContext="{d:DesignData /SampleData/StoreSampleData.xaml}"
    HeaderTemplate="{StaticResource myHeaderTemplate}"
    ItemTemplate="{StaticResource myItemTemplate}"
    SelectionChanged="ListView_SelectionChanged"
    Margin="10" Grid.Row="1">
</ListView>

リストビューにはヘッダ部分(HeaderTemplate)とアイテム部分(ItemTemplate)のテンプレートを指定できるのですが、ヘッダ部分もスクロールしてしまうんですよね…というか、どうやらアイテムの先頭だけを「ヘッダ」と言っているようです。英文の最初の文字を大きくするイメージでしょうか。日本のエクセル方眼紙にはなじめない文化ですよね、とか。

リソースは ListViewHeaderItem と ListViewItem の2つを作っておきます。ヘッダ部分の Text プロパティは直書きに、アイテムのほうはバインドしているのですが、これはフォームアプリのデータグリッドのように両方いっぺんにバインドをしたいところです。

    <DataTemplate x:Key="myHeaderTemplate">
        <Grid 
        Background="ForestGreen"
        Margin="1" Height="50" 
        >
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="1*"/>
                <ColumnDefinition Width="1*"/>
                <ColumnDefinition Width="1*"/>
                <ColumnDefinition Width="1*"/>
                <ColumnDefinition Width="1*"/>
            </Grid.ColumnDefinitions>
            <TextBlock Text="ID" FontSize="32" Grid.Column="0" />
            <TextBlock Text="Store" FontSize="32" Grid.Column="1" />
            <TextBlock Text="Sellingcompany" FontSize="32" Grid.Column="2" />
            <TextBlock Text="Areagroup" FontSize="32" Grid.Column="3" />
            <TextBlock Text="modified" FontSize="32" Grid.Column="4" />
        </Grid>
    </DataTemplate>
    <DataTemplate x:Key="myItemTemplate">
        <Grid 
                    Background="BlueViolet"
                    Margin="1" Height="50" Width="1030"
                    >
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="1*"/>
                <ColumnDefinition Width="1*"/>
                <ColumnDefinition Width="1*"/>
                <ColumnDefinition Width="1*"/>
                <ColumnDefinition Width="1*"/>
            </Grid.ColumnDefinitions>
            <TextBlock Text="{Binding ID}" FontSize="32" Grid.Column="0" />
            <TextBlock Text="{Binding Name}" FontSize="32" Grid.Column="1" />
            <TextBlock Text="{Binding Sellingcompany.Name}" FontSize="32" Grid.Column="2" />
            <TextBlock Text="{Binding Areagroup.Name}" FontSize="32" Grid.Column="3" />
            <TextBlock Text="{Binding modified}" FontSize="32" Grid.Column="4" />
        </Grid>
    </DataTemplate>

ColumnDefinition で等倍にしていますが、本来ならばサイズを指定したいところです。というか、自動的にサイズを計算してほしいところですね。このあたりの機能はあるかないか分かりません(たぶん無い)。1画面だけ作るのであれば、これでいいのですがマスター画面で十数画面を一気に作ろうと思うと結構面倒くさいことになります。まあ、マスター画面自体を「没入型」で作るかどうかは別だし。

■プロパティビューっぽいものとバインド用のモデル

プロパティビューのところは、GridView と同じです。ふつうにバインドしていけばOK。バインド用のモデルクラスも同じ。

■アイテムを選択したときのイベント

/// <summary>
/// アイテムを選択したとき
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    var item = e.AddedItems[0] as Model.Store;
    _model.Item = item;
}

やっていることは、「分割ページ」の ListView と同じなんですけどね。

■方眼紙っぽく枠線をつけてみる

縦横の線を書く、ってことはできなそうなので、まめに boarder をつけます。何気に面倒ですが、以下のように Border をちまちまつけていくと枠線が引けます…が、こんなことやるぐらいだったらコードで自動生成したいですよね。

<DataTemplate x:Key="myItemBTemplate">
    <Grid 
                Background="BlueViolet"
                Margin="1" Height="50" Width="1030"
                >
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="1*"/>
            <ColumnDefinition Width="1*"/>
            <ColumnDefinition Width="1*"/>
            <ColumnDefinition Width="1*"/>
            <ColumnDefinition Width="1*"/>
        </Grid.ColumnDefinitions>
        <Border BorderBrush="White" BorderThickness="2" Padding="3" Grid.Column="0" >
            <TextBlock Text="{Binding ID}" FontSize="32" />
        </Border>
        <Border BorderBrush="White" BorderThickness="2" Padding="3" Grid.Column="1" >
            <TextBlock Text="{Binding Name}" FontSize="32" />
        </Border>
        <Border BorderBrush="White" BorderThickness="2" Padding="3" Grid.Column="2" >
            <TextBlock Text="{Binding Sellingcompany.Name}" FontSize="32" />
        </Border>
        <Border BorderBrush="White" BorderThickness="2" Padding="3" Grid.Column="3" >
            <TextBlock Text="{Binding Areagroup.Name}" FontSize="32" />
        </Border>
        <Border BorderBrush="White" BorderThickness="2" Padding="3" Grid.Column="4" >
            <TextBlock Text="{Binding modified}" FontSize="32" />
        </Border>
    </Grid>
</DataTemplate>

罫線としてはいまいちだし、ヘッダ部分をクリックしたらソートしてほしいし、そのあたりも含めて ListView の自動生成機能が欲しいところです。

カテゴリー: CakePHP, WPF, WinRT | CakePHPのXMLレスポンスをListViewで一覧表示する はコメントを受け付けていません

CakePHPのXMLレスポンスをストアアプリで一覧表示する

CakePHPのXMLレスポンスをWPFで一覧表示する | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/5370

の Windows ストアアプリ版も作ってみます。

本当はListViewを使いたいところだけど、手始めに GridView を使うところから。もっと、WPFのListViewのようなダサいデザインを手軽に作れればいいのですが。どうもうまくいかない。

■データモデルを作る

WPFで作ったソースをそのまま流用しますが、一か所だけ違います。リフレクションでプロパティを取ってくるところで、拡張メソッドの GetTypeInfo を使います。なんで、こんな風にしたのか不明なのですが。

using System.Reflection;

public class IModel
{
    public void FormXml(XElement el)
    {
        // WinRTの場合
        var pis = this.GetType().GetTypeInfo().DeclaredProperties;
        foreach (var pi in pis)
        {
            var vv = el.Descendants(pi.Name).FirstOrDefault();
            if (vv != null)
            {
                var v = vv.Value;
                if (pi.PropertyType == typeof(int))
                    pi.SetValue(this, int.Parse(v));
                else if (pi.PropertyType == typeof(double))
                    pi.SetValue(this, double.Parse(v));
                else if (pi.PropertyType == typeof(string))
                    pi.SetValue(this, v);
            }
        }
    }
}

POJO なクラスはそのままで。

■グリッドビューを作る

VS2013 でグリッドのテンプレートを作ると、きれいな GridView のテンプレートを吐き出してくれるけどカスタムしにくいので、最小限のコードだけにします。

<GridView
    x:Name="itemGridView"
    ItemsSource="{Binding Items}"
    ItemTemplate="{StaticResource StoreTemplate}"
    Margin="13,13,10,10" Grid.Row="1"
    SelectionChanged="itemGridView_SelectionChanged">
</GridView>

データのバインドは「ItemsSource=”{Binding Items}”」なところで。このあたりは WPF と同じ。GirdView に表示するアイテムのテンプレートは、「ItemTemplate=”{StaticResource StoreTemplate}”」で指定してます。既存のデータテンプレートを使うと、バインド名が Title や Subtitle に固定になっているので、ここはカスタムで。StaticResource せずとも、GridView.ItemTemplate を使って以下のようにも書けます。

<GridView
    x:Name="itemGridView"
    ItemsSource="{Binding Items}"
    Margin="13,13,10,10" Grid.Row="1"
    SelectionChanged="itemGridView_SelectionChanged">
    <GridView.ItemTemplate>
        <DataTemplate>
            <Grid Width="200" Height="200">
                <TextBlock Text="{Binding ID}"  FontSize="20" Margin="10,10,10,150"   />
                <TextBlock Text="{Binding Name}" FontSize="20" Margin="10,50,10,97" />
            </Grid>
        </DataTemplate>
    </GridView.ItemTemplate>
</GridView>

1回だけしか使わない場合はこれで十分ですよね。そもそも、StaticResource って、その xaml 内に限るからあまりそこに書く理由はあまり意味ないかも、と思ってたり。

ページリソースに記述する場合はこんな感じで「StoreTemplate」のように名前を付けておきます。デザイン用のデータを読み込んでちまちま修正するパターンもできるので、これはこれで便利だし。他のプロジェクトからコピペする場合も便利。

<Page.Resources>
    <DataTemplate x:Key="StoreTemplate">
        <Grid Width="200" Height="200">
            <TextBlock Text="{Binding ID}"  FontSize="20" Margin="10,10,10,150"   />
            <TextBlock Text="{Binding Name}" FontSize="20" Margin="10,50,10,97" />
        </Grid>
    </DataTemplate>
</Page.Resources>

デザイン用のデータは、VS2013 から JSON 型式で読み込めるようになったのですが、何故か日本語が通りません。UTF-8 にしてもダメなので、なんか XAML デザイナのほうで変なことをやっている気がします。英語(ASCII文字)だけにすると通ります。

■プロパティビューっぽいもの

VS2013が作ってくれるデザインテンプレートでは、アイテムをクリックすると詳細画面に遷移しますが、ここは WPF と同じように同一の画面に表示させます。いちいち画面遷移するのも面倒だし(特に戻るのが面倒)、でかい画面を切り替えるよりも、画面を自前で分割するほうがいいよってことで。

<TextBox 
    Text="{Binding Item.ID}"
    Grid.Column="1" HorizontalAlignment="Left" Height="23" Margin="10,13,0,0" Grid.Row="1" TextWrapping="Wrap" VerticalAlignment="Top" Width="280"/>
<TextBox 
    Text="{Binding Item.Name}"
    Grid.Column="1" HorizontalAlignment="Left" Height="23" Margin="10,50,0,0" Grid.Row="1" TextWrapping="Wrap"  VerticalAlignment="Top" Width="280"/>
<TextBox 
    Text="{Binding Item.Sellingcompany.Name}"
    Grid.Column="1" HorizontalAlignment="Left" Height="23" Margin="10,87,0,0" Grid.Row="1" TextWrapping="Wrap"  VerticalAlignment="Top" Width="280"/>
<TextBox 
    Text="{Binding Item.Areagroup.Name}"
    Grid.Column="1" HorizontalAlignment="Left" Height="23" Margin="10,124,0,0" Grid.Row="1" TextWrapping="Wrap" VerticalAlignment="Top" Width="280"/>

バインドは、Item の下にプロパティをつける形にしておきます。この構造は、先のデータモデルと合わせておきます。当然名前も一緒にしないとダメ。

■バインド用のモデルを作る

ここは WPF と同じ。

public class BindModel : BindableBase
{
    private ObservableCollection<Model.Store> _Items;
    public ObservableCollection<Model.Store> Items
    {
        get { return _Items; }
        set { this.SetProperty(ref this._Items, value); }
    }

    private Model.Store _Item;
    public Model.Store Item
    {
        get { return _Item; }
        set { this.SetProperty(ref this._Item, value); }
    }
}

■DataContextに設定する

DataContext に設定する方法も同じ。ストアアプリでは、DefaultViewModel がある訳ですが、実質同じことをやるので、どちらかを使えば OK です。

[win8] DefaultViewModel と DataContext は同時に使えない | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/3873

に書いた通り「バインディングするところがアレ」なので、DataContext で十分かなと思ったりします。コードレベルで WPF との共有も考えると、業務コード的にはどっちかに統一しておいたほうがよいかも。覚えることが少なくなるし。

public sealed partial class MainPage : Page
{
    public MainPage()
    {
        this.InitializeComponent();
        // モデルをバインドする
        _model = new BindModel();
        this.DataContext = _model;
    }

    private BindModel _model;

    /// <summary>
    /// 一覧を取得
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private async void Button_Click(object sender, RoutedEventArgs e)
    {
        var lst = await new Api.ApiStore().Read();
        _model.Items = new ObservableCollection<Model.Store>(lst);
    }
    /// <summary>
    /// アイテムをクリックしたとき
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void itemGridView_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        var item = e.AddedItems[0] as Model.Store;
        _model.Item = item;
    }
}

これで API 呼び出しをして、GridView のアイテムをちまちまとクリック(タブレットの場合はタップ)すると、詳細情報が右のプロパティ一覧に表示されます。

ちなみに、WPFでテキストボックスにバインドをすると初期値が TwoWay(双方向)になっていますが、ストアアプリの場合は OneWay(表示のみ)です。あとストアアプリの場合、それぞれのプロパティに INotifyPropertyChanged をつけないと、TwoWay にならないのが面倒かなと。このあたり VS2012 のグリッドのサンプルにはあったのだけど、VS2013 のグリッドのサンプルにはないんですよね。

GridView の場合は横スクロールなので、お次は ListView を使って縦スクロール(WPFのリスト表示と同じパターン)で作ってみます。

カテゴリー: CakePHP, WPF, WinRT | CakePHPのXMLレスポンスをストアアプリで一覧表示する はコメントを受け付けていません

CakePHPのXMLレスポンスをWPFで一覧表示する

余裕があるうちにCakePHPとWPFの相互運用をまとめていく(準備編) | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/5329

の続きで、今度はWPF側からのコーディングです。
いわゆる、以下な感じな、リストビューとプロパティを表示するマスター画面を想定します。

一覧ボタンを押すと、Web APIにつなげて一覧を取得。リストビューの各行をクリックすると右側のプロパティに詳細な値がぽちぽちと表示されるパターンです。このあたり、WPFなので、適当に Binding を使います。最終的には、Visual Studio のプロパティウィンドウのように自動化を目指したいところなのですが…まあ、業務的には各種のプロパティウィンドウをちまちま作っています。というのも、完全に自動化してしまうと使い勝手が悪いことがある(データベース構造に引きずられる)ことになるので、このあたりは適宜カスタムで。
とはいえ、cake bake で自動化できるぐらいには、受け側の WPF のマスター画面も自動化生成しておきたいところです。

■データモデルを作る

まずは、Model を作ります。お店(Store)クラスは、会社(Sellingcompany)と地域(Areagroup)が紐づいているので、Storeクラスの中にプロパティとして入れてしまいます。このあたりの構造は、CakePHPが返すXMLがフラットな構造(Store, Sellingcompany, Areagroupが並列で存在)に対して、モデルのほうはツリー構造になります。IModel.FormXml メソッドは、XElement から適当にモデルにプロパティを入れ込むための簡易メソッドです。業務のほうは ExDoc を使ってみましたが、試しに XElement.Descendants を使ってパース。

  • Web APIが返す要素名
  • 受け取るときのクラス名
  • 受け取るときのプロパティ名

を大文字小文字も合わせて完全に一致させておくと、この方法が取れます。逆に言えば、それぞれの名前が微妙に違ったリスト面倒なことになるわけですが…まあ、そのときは属性を使って回避するのもよし、ここの FromXmlで書き換えるもよし、というところです。

public class IModel
{
    public void FormXml(XElement el)
    {
        var pis = this.GetType().GetProperties();
        foreach (var pi in pis)
        {
            var vv = el.Descendants(pi.Name).FirstOrDefault();
            if (vv != null)
            {
                var v = vv.Value;
                if (pi.PropertyType == typeof(int))
                    pi.SetValue(this, int.Parse(v));
                else if (pi.PropertyType == typeof(double))
                    pi.SetValue(this, double.Parse(v));
                else if (pi.PropertyType == typeof(string))
                    pi.SetValue(this, v);
            }
        }
    }
}

public class Store : IModel
{
    public int ID { get; set; }
    public int SellingCompanyID { get; set; }
    public int AreaGroupID { get; set; }
    public string Code { get; set; }
    public string Name { get; set; }
    public string Person { get; set; }
    public string Tel { get; set; }
    public string EMail { get; set; }
    public string ApplicationProgress { get; set; }
    public int Enabled { get; set; }
    public DateTime modified { get; set; }
    public DateTime created { get; set; }
    // リンク先
    public Areagroup Areagroup { get; set; }
    public Sellingcompany Sellingcompany { get; set; }

    public Store(XElement el)
    {
        base.FormXml(el);
        this.Areagroup = new Areagroup(el.Parent.Descendants("Areagroup").FirstOrDefault());
        this.Sellingcompany = new Sellingcompany(el.Parent.Descendants("Sellingcompany").FirstOrDefault());
    }
}
public class Areagroup : IModel
{
    public int ID { get; set; }
    public string Name { get; set; }
    public string DisplayName { get; set; }
    public int SortKey { get; set; }
    public int ColorR { get; set; }
    public int ColorG { get; set; }
    public int ColorB { get; set; }
    public int ForeColorBW { get; set; }
    public int ExcelColor { get; set; }
    public int Enabled { get; set; }
    public DateTime modified { get; set; }
    public DateTime created { get; set; }

    public Areagroup(XElement el) { base.FormXml(el); }
}

public class Sellingcompany : IModel
{
    public int ID { get; set; }
    public int ManufacturerID { get; set; }
    public int JurisdictionID { get; set; }
    public string Name { get; set; }
    public string Abbreviation { get; set; }
    public string Code { get; set; }
    public int Enabled { get; set; }
    public DateTime modified { get; set; }
    public DateTime created { get; set; }

    public Sellingcompany(XElement el) { base.FormXml(el); }
}

それぞれのプロパティはちまちまと書いてもいいのですが、Visual Studio 2013 だと「編集」メニューの「型式を選択して貼り付け」→「XMLをクラスとして貼り付ける」を選ぶと簡単に作れます…が、JSONのときとXMLの時と違う出力になるので、なんだかな~という感じなのと、MVVM の Model にするときはちまちまと手作業で変えないといけません。まあ、その時は適当なスクリプトを書けば済むわけですが。
Store クラスのコンストラクタがややこしいことになっているのは、Web APIが返すXML構造とModel.Storeクラスのツリー構造が異なるからです。ここを同じにしてもよいのですが、CakePHPの出力とWPFでバインドをするときの便利さとが異なるの、ここで調節しておくほうがベターです。

■リストビューを作る

左側のリストビューを作ります。DataContextを使ったデータバインドが前提になるので、ちまちまとバインド式を書いてきます。

最低限バインドしておく箇所は、

  • ListView に ItemsSource=”{Binding Items}” でバインド
  • それぞれの列に DisplayMemberBinding=”{Binding ID}” でバインド

ビューにバインドするモデルから Items プロパティで bind させます。そして、それぞれのアイテム(要素)のプロパティにバインドさせるわけですが、DisplayMemberBinding=”{Binding Sellingcompany.Name}” のように、内部もつクラスのプロパティを参照することができます。ツリー構造にしておくと、親オブジェクトをリスト化しておいて、それぞれのプロパティにアクセスができます。

<ListView 
    x:Name="lv"
    ItemsSource="{Binding Items}"
    SelectionChanged="lv_SelectionChanged"
    HorizontalAlignment="Left" Height="235" Margin="10,10,0,0" Grid.Row="1" VerticalAlignment="Top" Width="315">
    <ListView.View>
        <GridView>
            <GridViewColumn Header="ID" 
                            DisplayMemberBinding="{Binding ID}" Width="50"/>
            <GridViewColumn Header="名前" 
                            DisplayMemberBinding="{Binding Name}" Width="50"/>
            <GridViewColumn Header="会社名" 
                            DisplayMemberBinding="{Binding Sellingcompany.Name}" Width="50"/>
            <GridViewColumn Header="地域" 
                            DisplayMemberBinding="{Binding Areagroup.Name}" Width="50"/>
        </GridView>
    </ListView.View>
</ListView>

プロパティが入れ子になってバインドができるのは便利なのですが、逆に言えばプロパティ名が変わったときには、XAML 部分も直さないといけないという弊害もあります。そのあたりは先の Web API とデータモデルの自動変換のところにも当てはめるわけで、それはそれで割り切りで。業務のほうは、SellingcompanyName という読み取り専用のプロパティを作ったりしてます。

■プロパティビューっぽいものを作る

リストビューをクリックしたときの内容を表示させます。
リストビューと似た形で Item という名前で DataContext へバインドしておきます。この「Item」の部分は、自分で好きなように設定できます。

<TextBox 
    Text="{Binding Item.ID}"
    Grid.Column="1" HorizontalAlignment="Left" Height="23" Margin="10,13,0,0" Grid.Row="1" TextWrapping="Wrap" VerticalAlignment="Top" Width="162"/>
<TextBox 
    Text="{Binding Item.Name}"
    Grid.Column="1" HorizontalAlignment="Left" Height="23" Margin="10,41,0,0" Grid.Row="1" TextWrapping="Wrap"  VerticalAlignment="Top" Width="162"/>
<TextBox 
    Text="{Binding Item.Sellingcompany.Name}"
    Grid.Column="1" HorizontalAlignment="Left" Height="23" Margin="10,69,0,0" Grid.Row="1" TextWrapping="Wrap"  VerticalAlignment="Top" Width="162"/>
<TextBox 
    Text="{Binding Item.Areagroup.Name}"
    Grid.Column="1" HorizontalAlignment="Left" Height="23" Margin="10,97,0,0" Grid.Row="1" TextWrapping="Wrap" VerticalAlignment="Top" Width="162"/>

Text=”{Binding Item.ID}” のところがバインドですね。地域の名前を表示するときは Text=”{Binding Item.Areagroup.Name}” な感じでバインドさせます。
TextBox にバインドさせているのは、編集もできるようにするためです。ただし、不用意に編集されないように読み取り専用のときと編集可能なときのモードをつけるほうがベターです。これは、IsEnabled に対してバインドさせると一気に Textbox を読み取り専用にすることができます。

■バインド用のモデルを作る

WPFのビューにバインドさせるモデルクラスを作ります。INotifyPropertyChanged インターフェースを使うわけですが、Visual Studio 2012 に入っているストアアプリ用の BindableBase.cs をそのまま使っています。このあたりは適宜好み&用途にあわせて。

public class BindModel : BindableBase
{
    private ObservableCollection<Model.Store> _Items;
    public ObservableCollection<Model.Store> Items
    {
        get { return _Items; }
        set { this.SetProperty(ref this._Items, value); }
    }

    private Model.Store _Item;
    public Model.Store Item
    {
        get { return _Item; }
        set { this.SetProperty(ref this._Item, value); }
    }
}

リストのほうは、ObservableCollection を使うのを忘れずに。
本来ならば Model.Store クラスの各プロパティも INotifyPropertyChanged を通すべきなのですが、単なる閲覧の場合は不要なのでこのままで。
Items コレクションがリストビューにバインドするプロパティで、Item プロパティがプロパティウィンドウのほうにバインドするものです。

■DataContextに設定する

ビューの DataContext にモデルを結びつけます。XAMLにStaticResourceで追加してもよいのですが、好みコードで設定しています。

public MainWindow()
{
    InitializeComponent();
    // モデルをバインドする
    _model = new BindModel();
    this.DataContext = _model;
}
private BindModel _model;

/// <summary>
/// 一覧を取得
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void Button_Click(object sender, RoutedEventArgs e)
{
    var lst = await new Api.ApiStore().Read();
    _model.Items = new ObservableCollection<Model.Store>(lst);

    // this.lv.ItemsSource = lst;
}

/// <summary>
/// 項目を選択
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void lv_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    var item = lv.SelectedItem as Model.Store;
    _model.Item = item;
}

リストビューの更新は、_model.Items 経由で、リストビューの行を選択したときは _model.Item 経由で表示させます。
CakePHP で作った Web API の呼び出しが new Api.ApiStore() となっているのは愛嬌です。本来ならば static メソッドにするか、別途 api 用のオブジェクトをキープしておくかという感じなんですが、まあ、new 使ってガシガシと開くところは Java っぽいですね。この new オブジェクトはいつ解放されるのだろうか?ってなことは C++ の時だけ考えます。

■Web APIを呼び出す

Web API の呼び出し部分も定型なので、何かと共通化しておきたいところですが、いまんところべた書きです。どうしても Store のようなクラス名が出てきてしまうので、あまり汎用的には作れません。T4 使って自動生成するぐらいかなと。エラー処理がおおざっぱなのは、所詮マスター画面で使うものだからです。基本はエラーがでないという思想ですね。

public async Task<List<Model.Store>> Read()
{
    var uri = new Uri(SERVER + "/Stores.xml");
    var lst = new List<Model.Store>();
    try
    {
        HttpClient cl = new HttpClient();
        var xml = await cl.GetStringAsync(uri);
        var doc = XDocument.Parse(xml);
        var coll = doc.Descendants("item");
        foreach (var it in coll)
        {
            var el = it.Descendants("Store").FirstOrDefault();
            var m = new Model.Store(el);
            lst.Add(m);
        }
    }
    catch ( Exception ex )
    {
        // エラー発生
        Debug.WriteLine("error:{0}", ex.Message);
        return lst;
    }
    return lst;
}
public async Task<Model.Store> Read( int id )
{
    var uri = new Uri(SERVER +
        string.Format("/Stores/view/{0}.xml", id));
    try
    {
        HttpClient cl = new HttpClient();
        var xml = await cl.GetStringAsync(uri);
        var doc = XDocument.Parse(xml);
        var el = doc.Descendants("Store").FirstOrDefault();
        var m = new Model.Store(el);
        return m; 
    }
    catch (Exception ex)
    {
        // エラー発生
        Debug.WriteLine("error:{0}", ex.Message);
        return null;
    }
}

Web APIのエラー値を取るためには、もう少しコードを追加しないといけません。
ひとまず、こんな感じで WPF から CakePHP の Web API を呼び出すことができます。

カテゴリー: CakePHP, WPF | CakePHPのXMLレスポンスをWPFで一覧表示する はコメントを受け付けていません

CakePHPのWeb APIレスポンスをJSON型式で返す

業務では使わなかったのですが、JSON型式で返す方法も紹介しておきます。

1. app/Config/routes.php を書き換える

先頭の行に以下を追加します。

	Router::parseExtensions('json');

以下のように並べると、xml と json の両方が使えます。

	Router::parseExtensions('json','xml');

2. app/Controller/AppController.php を書き換える

RequestHandler コンポーネントを有効にすること、ページングの数を多めにとっておきます。

class AppController extends Controller {
	public $components = array('RequestHandler');
	public $paginate = array( 'limit' => 1000 );
}

3. XML 用の View を作成する

Controller で set した値を json/*.ctp ファイルに書いていきます。作るファイルは XML と同じで、index.ctp, view.ctp, add.ctp, edit.ctp になります。json に変換する場合は、json_encode 関数です。

index.ctp は、配列にします。

$items = array('items'=> array('item'=> $stores));
echo json_encode(array('response'=>$items),JSON_UNESCAPED_UNICODE);

view.ctp, add.ctp, edit.ctp は一つだけの要素を返します。

$item = array('item'=> $store);
echo json_encode(array('response'=>$item),JSON_UNESCAPED_UNICODE);

# この部分、なんとか汎用化できないかと思案中。
JSON_UNESCAPED_UNICODE は、マルチバイトを uXXXX 形式にしない、という設定です。こっちのほうがデコードする手間が省けるので。

■実行してみる

一覧の場合は、http://localhost:81/cakephp-2.4.5/Stores.json 、IDを指定して閲覧する場合は http://localhost:81/cakephp-2.4.5/Stores/view/20.json

■おまけ

似た感じでスクリプトも書いておきます。

<?php
$views = array( 
	array('adjustmentjobs', 'adjustmentjob'),
...
	array('stores', 'store'),
	array('workingsituations', 'workingsituation'),
);

foreach ( $views as $v ) 
{
	$v0 = $v[0];
	$v1 = $v[1];
	
	$json0 =<<< END
<?php 
$items = array('items'=> array('item'=> $$v0));
echo json_encode(array('response'=>$items));

END;

	mkdir("view/$v0/json");
	$path="view/$v0/json/index.ctp";
#	print "$json0n";
	file_put_contents( $path, $json0 );

	$json1 =<<< END
<?php 
$item = array('item'=> $$v1);
echo json_encode(array('response'=>$item));

END;

#	print "$json1n";
	file_put_contents( "view/$v0/json/view.ctp", $json1 );
	file_put_contents( "view/$v0/json/add.ctp", $json1 );
	file_put_contents( "view/$v0/json/edit.ctp", $json1 );
}
カテゴリー: CakePHP, WPF | CakePHPのWeb APIレスポンスをJSON型式で返す はコメントを受け付けていません

CakePHPのWeb APIレスポンスをXML型式で返す

CakePHP の通常 View ができたので、XML を返す Web API用のビューを作ります。

[CakePHP] RESTを使ってViewをXML形式で返す | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/4871

と基本は同じです。View の各フォルダに xml フォルダを作成して対応させます。いちいち同じファイルを作らないといけないのが面倒ですが、適当なスクリプトを作って自動化させておくとよいでしょう。

1.app/Config/routes.php を書き換える

先頭の行に以下を追加します。

	Router::parseExtensions('xml');

2.app/Controller/AppController.php を書き換える

RequestHandler コンポーネントを有効にすること、ページングの数を多めにとっておきます。

class AppController extends Controller {
	public $components = array('RequestHandler');
	public $paginate = array( 'limit' => 1000 );
}

デフォルトでは 20 件ぐらいなのですが、XML型式の場合はそれでは不便です。なので1000件をlimitにしておきます。本当はコントローラごとに細かく制限するのがよいのですが、それはシステム特性というとで、ひとまずこうしておくと大丈夫です。この数をもっと大きくしてもいいのですが、レスポンスも悪くなるし、システム的にこのぐらいがしておく、という感じですね。

3.XML 用の View を作成する

Controller で set した値を xml/*.ctp ファイルに書いていきます。CURD すべてに対応するために、index.ctp, view.ctp, add.ctp, edit.ctp を作っておけば OK です。

index.ctp は、配列にします。

$items = array('items'=> array('item'=> $stores));
$xml = Xml::fromArray(array('response'=>$items));
echo $xml->asXML();

view.ctp, add.ctp, edit.ctp は一つだけの要素を返します。

$item = array('item'=> $store);
$xml = Xml::fromArray(array('response'=>$item));
echo $xml->asXML();

response 要素を作って、その中に items あるいは item を作っていますが、これは好みですね。どちらもルート要素はひとつになるので、response は必要ないのですが、受け取る側(この場合は WPF )で、同じ名前のほうがいいだろうと思ってこうしています。
ただし、これだと web api の OK/NG が返しにくいのが難点です。Web API の受け取り側のつくりとしては、

  • API自体の成功/失敗を早めに拾いたい
  • APIレスポンスの型式はできるだけ同じ形式であってほしい。
  • OK/NGのレスポンスはできるだけ同じ形式であってほしい。

というのがあります。XMLをパースするときに、指定の要素があったりなかったりすのは結構面倒です。また、正常時のXML構造と異常時にXML構造は同じであったほうがプログラムが簡単になります。そうい意味では、あらかじめ response の属性として OK/NG をつけたりバージョンをつけるのがよいのですが…今回は、最初の実装時に入れ忘れたのこのままです。
あと、xml/*.ctp 自体は、非常に単純にしておかないとデバッグが面倒なんですよね。なので、できるだけ簡単にするために、こんなスタイルにしてます。

■一覧(index)を実行すると

XML 型式で返す場合は、http://localhost:81/cakephp-2.4.5/Stores.xml のように、最後に「.xml」をつけます。こうすると、$belongsTo などで指定したアソシエーションと一緒にデータを取得できます。

レスポンス自体には一切改行がないので閲覧には不便なので、IEなどのブラウザを利用するとよいです。

■ひとつの要素(view)を実行する

ID を指定して表示したい場合は、http://localhost:81/cakephp-2.4.5/Stores/view/20.xml のように指定します。最後に「.xml」をつければいいので、他の edit や add も同じです。

似た感じに見えますが、一覧の場合は response/items/item の中にそれぞれの要素が入っていて、view の場合は response/item の中に要素が入っています。
この入れ子が面倒な場合は、

$items = array('items'=> array('item'=> $store));
$xml = Xml::fromArray(array('response'=>$items));
echo $xml->asXML();

のように items 要素を入れてしまってもいいと思います。こうすることで、ひとつでも複数の要素でも、response/items/item の階層でデータが取れます。こっちのほうがいいかもしれませんね。

■add/edit はどうするのか?

add も edit もレスポンスとしては view と同じです。が、新規に作成したり編集したりするデータをクライアントから送らないといけません。ブラウザから編集するページは cake bake で自動生成しているので、WPF クライアントからサーバーへ POST するプログラムを作ります。これはちょっと次回へ。

■おまけ

適当ですが、こんな風にスクリプトを書いて、xml/*.ctp を作成します。
app フォルダに allbakexml.php のファイルで保存して実行してください。$views に複数形、単数形の順に書かないとダメなのは、Controller か Model の中身を見るようにすれば汎用化できるかも。

<?php
$views = array( 
	array('adjustmentjobs', 'adjustmentjob'),
...
	array('stores', 'store'),
	array('workingsituations', 'workingsituation'),
);

foreach ( $views as $v ) 
{
	$v0 = $v[0];
	$v1 = $v[1];
	
	$xml0 =<<< END
<?php 
$items = array('items'=> array('item'=> $$v0));
$xml = Xml::fromArray(array('response'=>$items));
echo $xml->asXML();

END;

	mkdir("view/$v0/xml");
	$path="view/$v0/xml/index.ctp";
#	print "$xml0n";
	file_put_contents( $path, $xml0 );

	$xml1 =<<< END
<?php 
$item = array('item'=> $$v1);
$xml = Xml::fromArray(array('response'=>$item));
echo $xml->asXML();

END;

#	print "$xml0n";
	file_put_contents( "view/$v0/xml/view.ctp", $xml1 );
	file_put_contents( "view/$v0/xml/add.ctp", $xml1 );
	file_put_contents( "view/$v0/xml/edit.ctp", $xml1 );
}
カテゴリー: CakePHP, WPF | CakePHPのWeb APIレスポンスをXML型式で返す はコメントを受け付けていません