Quantcast
Channel: かずきのBlog@hatena
Viewing all 1387 articles
Browse latest View live

awaitでLazyみたいなことをしたい

$
0
0

以前にid:neueccさんが、Build Insider Offlineで披露してたAsyncLazyがかっこよかったので元ネタからソースを拝借。

publicclass AsyncLazy<T> : Lazy<Task<T>>
{
    public AsyncLazy(Func<T> valueFactory) :
        base(() => Task.Factory.StartNew(valueFactory)) { }

    public AsyncLazy(Func<Task<T>> taskFactory) :
        base(() => Task.Factory.StartNew(() => taskFactory()).Unwrap()) { }

    public TaskAwaiter<T> GetAwaiter() { return Value.GetAwaiter(); }
}

Lazy<T>のTの部分をTask<T>にしてGetAwaiterを定義してやるだけでawaitで値をとってこれるLazyができちゃうなんて柔軟すぎる…。気になるのはid:neueccさんが、ちょっと手を入れて使ってますといったところ。何かこれで不都合がでたのかなぁ。

あとスライドにしれっとAsyncLazy.WhenAll(p.Name, p2.Name, p3.Name)みたいなものが出てたけどAsyncLazyがTaskを包んだだけのLazyだとしたら以下のような実装でAsyncLazyの実装はいけそう?

publicstaticclass AsyncLazy
{
    publicstatic Task WhenAll<T>(params AsyncLazy<T>[] ls)
    {
        // Lazy<Task<T>>[]からTask<T>[]に変換してTask.WhenAllするreturn Task.WhenAll(ls.Select(l => l.Value).ToArray());
    }
}

ふむふむ。


WinRT XAML Toolkitでチャートを表示する

$
0
0

使い方に関する情報が割と少な目だなと思ったので…。コードレシピにサンプルあげてみました。
使い方がわかると、簡単にできますね!色のカスタマイズ方法とか、いざとなればコントロールテンプレートを差し替えて思いのままに表示とかできるのかな…。ということを考えてしまいます。

WinRT XAML Toolkitでチャートを表示する

colorisというストアアプリ

$
0
0

colorisというストアアプリが初音さんからリリースされました!

このアプリは、Windows ストアアプリを開発する人がいい感じの配色のアプリを作るためのリソースをはいてくれる素敵なアプリです。そして、何よりも設定チャームのバージョン情報にあるCOPYRIGHTの面子を見て一番びっくりするアプリです。こわい。

Cardフリップ?なCheckBox

$
0
0

みつばたん(id:c-mitsuba)がcafe. Blend #2で作ってたくるりんと回るCheckBoxに魅せられて自分でも作ってみました。

コードはこちらから。
http://sdrv.ms/13rI8wg

みつばたん先生からは、縦になったときに消える時間が長いというご指摘なので、もう一度再調整する!

Prism.PubSubEventのサンプルを書いてみました

$
0
0

Prism for Windows Runtimeの中でポータブルクラスライブラリとして公開されているPrism.PubSubEventのサンプルをコードレシピに書いてみました。
以下から見れます!

Prism.PubSubEventのサンプル

LightSwitch(HTML Client)のVisual Collection覚書

$
0
0

リファレンス的なドキュメントってどこにあるんでしょう…LightSwitchのJavaScriptライブラリ達。(コードがドキュメント?)
とまぁいきなり愚痴ですが、ちょいちょいとLightSwitchのHTML Clientを触ってみてます。こいつは、なかなかデキルやつでレスポンシブでタッチフレンドリーなUIをさくさくと作れる優れもの。JavaScriptを要所要所で書くことが出来るので、その気になればダサいテーブルとかも自分で組み込むことが出来ちゃう。つまり細部まで知ったうえで使えば、簡単なアプリ作りをするうえでの心強い味方になってくれる可能性が無きにしも非ずな可能性を感じます。

ということで、今日の本題。

JavaScriptのVisualCollection覚書

色々試してて、データを読み込んだりするのに使ったメソッドとかです。

VisualCollectionの取得方法

ページにProductsというクエリやテーブルを作ってる場合は、以下のようなJavaScriptで取得できる。

var collection = screen.Products;

その他に、Productsをレンダリングするカスタムコントロールの場合は、関数の引数のcontentItemのvalueがProductsのVisualCollectionになってる

myapp.BrowseProducts.ProductsItem_render = function (element, contentItem) {
  var collection = contentItem.value; // これで取得できる
}
読み込み完了かどうかの判定と読み込み

isLoadedプロパティで読み込み完了かどうか確認できる。falseの場合はloadメソッドを使ってデータの読み込みを行う。

var collection = contentItem.value;
// renderRowsというデータを描画する関数があるとする
function isLoadedChanged() { renderRows(collection.data); }
if (collection.isLoaded) {
    // 読み込み済みならレンダリングする
    renderRows(collection.data);
} else {
    // 読み込み済みじゃないならisLoadedにイベントハンドラしかけて、loadを呼ぶ
    collection.addChangeListener('isLoaded', isLoadedChanged);
    collection.load();
}
実際に読み込まれてるデータを取得する

上の例でも出てますがdataで取得できます。

var collection = contentItem.value;
// 読み込み済みデータを取得(配列になってる)
var items = collection.data;
続きを読み込む

canLoadMoreプロパティで、まだ続きのデータを読み込めるか判定して、読み込めるようならloadMoreメソッドで読み込みを行う。loadMoreメソッドはPromiseを返すのでthenとかで繋げて読み込み完了時の処理とかが書ける。

// まだ続きがあるか確認
if (screen.Products.canLoadMore) {
    // 続きがあるならloadMoreで読み込む。
    screen.Products.loadMore().then(function (result) {
        // 読み込み結果はitemsで取得できる
        renderRows(result.items);
    });
}
選択中のアイテムを取得

selectedItemプロパティで取得・設定可能。

// 選択中のアイテムを取得
var item = screen.Products.selectedItem;

LightSwitch(HTML Client)からASP.NET WebAPIを呼ぶ

$
0
0

まぁ、JavaScriptなんで簡単に呼べますよね。
Global.asaxを作成してApplication_StartにWebAPI用のルートの設定を追加。

RouteTable.Routes.MapHttpRoute(
    "default",
    "api/{controller}/{id}",
    new { id = RouteParameter.Optional });

Controller名前空間あたりに、AuthInfoControllerを作って以下のような内容で作成。とりあえず、ログインユーザー名を返すようにしてみた。LightSwitchが自動生成してくれるServerApplicationContextを使うとデータアクセスとか認証情報へのアクセスとかが出来るのでいい感じ。ASP.NET WebAPIやWebFormやMVCからも使えるので、うまいこと部分的にLightSwitchで作って手を抜きつつ、力を注ぐべきところはWebAPIとMVCで作るとかいう使い分けができるかも?

using System.Web.Http;

namespace LightSwitchApplication.Controller
{
    publicclass AuthInfoController : ApiController
    {
        // GET api/<controller>publicstring Get()
        {
            using (var context = ServerApplicationContext.Current ?? ServerApplicationContext.CreateContext())
            {
                return context.Application.User.Identity.Name;
            }
        }
    }
}

あとは、ページでAdd Data Item...でString型のLoginUserというプロパティを追加して画面の抵当なところに落としてからWrite Code...からcreatedを選んで生成された関数内にjQueryのajaxメソッドを使ってデータをとってきてから画面のLoginUserに設定してやる。

/// <reference path="../GeneratedArtifacts/viewModel.js" />

myapp.BrowseUsersSet.created = function (screen) {
    // Write code here.
    msls.promiseOperation(function (promise) {
        $.ajax({
            url: "../api/authInfo",
            success: function (result) {
                promise.complete(result);
            },
            error: function (e) {
                promise.error(e);
            }
        });
    }).then(function (result) {
        screen.LoginUser = result;
    });
};

msls.promiseOperationでWinJSのPromiseにラップしてるのは必須なのかは要調査。必須じゃなかったらsuccessのコールバック内で直接screen.LoginUserに代入してもいいもんなぁ。

とまぁ、こんな感じでLightSwitchの認証情報からユーザー名を返すWebAPIを作りつつ、それを画面から呼んで結果を表示するというのは割と簡単にできました。めでたしめでたし。

LightSwitch(HTML Client)でjsRenderを使ってテーブルを表示してみた

$
0
0

CodeZineでjsRenderというものを知りました。

これは、面白そうということでぐぐってたら公式ページとともにMSDNマガジンの記事が…!?華麗にスルーしてたけど、公式とあわせて読むととりあえず大体OKっぽい。

LightSwitchはjQueryとjQuery mobileが使えたりするので、jQuery mobileのテーブルの出し方はこちらを参考にしました。

最近の個人的なJavaScriptの遊び場

こういうJavaScriptで遊ぶ時は最近LightSwitchのHTMLClientを使ってます。お手軽に基本的な画面は作れてJavaScriptで色々いじくるための骨組みができるのでとってもいい感じです。

jsRenderの取り込み

jsRenderの公式からjsviews.min.jsをDLしてきてLightSwitchのFileViewにしてScriptsフォルダに置きます。ついでに、LightSwitchのランタイム自体もNuGetで更新してテーマもダークにしてみました。*2
default.htmのcssのファイル名をバージョンアップしたcssのバージョン番号とあうように変更します。

<linkrel="stylesheet"type="text/css"href="Content/dark-theme-1.0.1.css" /><linkrel="stylesheet"type="text/css"href="Content/msls-dark-1.0.1.css" /><linkrel="stylesheet"type="text/css"href="Content/jquery.mobile.structure-1.3.1.min.css" /><linkrel="stylesheet"type="text/css"href="Content/msls-1.0.1.min.css" />

そして、scriptタグもバージョン番号を変えるのとjsRenderのJavaScriptを読み込むようにします。

<scripttype="text/javascript"src="//ajax.aspnetcdn.com/ajax/globalize/0.1.1/globalize.min.js"></script><scripttype="text/javascript"src="Scripts/winjs-1.0.min.js"></script><scripttype="text/javascript"src="Scripts/jquery-1.9.1.min.js"></script><scripttype="text/javascript"src="Scripts/jquery.mobile-1.3.1.min.js"></script><scripttype="text/javascript"src="Scripts/datajs-1.1.0.min.js"></script><scripttype="text/javascript"src="Scripts/Generated/resources.js"></script><scripttype="text/javascript"src="Scripts/msls-1.0.1.min.js"></script><scripttype="text/javascript"src="Scripts/Generated/generatedAssets.js"></script><scripttype="text/javascript"src="Scripts/jsviews.min.js"></script>

データの作成

とりあえず簡単にデータを定義します。NameとAgeを持っただけのシンプルなデータです。
f:id:okazuki:20130807232137p:plain
こいつを表示するためのBrowseページと編集追加する画面を適当に定義します。そして、その画面を使って4件くらいデータを入れました。
f:id:okazuki:20130807232607p:plain

jsRenderで遊ぶ

ついに本題です。jsRenderで遊びましょう。Personとして定義したデータを表示したいので、NameとAgeを持つテーブルの行を表示するテンプレートをdefault.htmに以下のように定義してみました。

<!-- テーブルのヘッダー部のテンプレート(固定テキストだからテンプレートにする必要性はないかも?) --><scriptid="personHeaderRowTemplate"type="text/x-jsrender"><tr><th>名前</th><th>年齢</th></tr></script><!-- Personをテーブルの行として展開するテンプレート。名前はHTMLエンコードする --><scriptid="personRowTemplate"type="text/x-jsrender"><tr><td>{{html:Name}}</td><td>{{:Age}}</td></tr></script><!-- Personの配列をテーブルの行として展開するテンプレート --><scriptid="personRowsTemplate"type="text/x-jsrender">{{for rows tmpl="#personRowTemplate"/}}</script>

最初のはヘッダー。あとはテーブルのボディ部です。最後のテンプレートでforを使って複数行のデータの展開にも対応しています。テンプレートの定義ができたので、default.htmのreadyメソッドで、テンプレートを読み込んでおきます。

<scripttype="text/javascript">    $(document).ready(function(){// テンプレートを読み込んでおく        $.templates("personHeaderRowTemplate", "#personHeaderRowTemplate");        $.templates("personRowTemplate", "#personRowTemplate");        $.templates("personRowsTemplate", "#personRowsTemplate");        msls._run()
        .then(null, function failure(error){alert(error);});});</script>

あとはBrowseのページにタブを新規追加して、そこにPersonSetのデータをレンダリングするカスタムコントロールを定義してレンダリング処理をかいていきます。ここらへんは定型句なんですが、jsRenderのおかげで退屈なHTML組み立て処理がかなりすっきりしています。
ちょっと困ったのは、jsRenderで作ったHTMLを$()に食わせるとエラーになったのでdivタグを作って、そこに流し込んでcontentsでjQueryのオブジェクトとして取り出しています。
*3

/// <reference path="../GeneratedArtifacts/viewModel.js" />/// <reference path="../Scripts/jsviews.min.js" />

myapp.BrowsePersonSet.PersonSet_render = function (element, contentItem) {var $element = $(element);
    // テーブルの骨組みを組み立てる。jquery mobileのテーブルを使うvar table = $('<table id="peopleTable" data-role="table" class="ui-responsive"/>')
        .appendTo($element);
    // ヘッダvar headerHtml = $.render.personHeaderRowTemplate();
    $('<thead />')
        .html(headerHtml)
        .appendTo(table);
    // ボディvar tbody = $('<tbody />').appendTo(table);

    var c = contentItem.value;

    // コレクションのデータをレンダリングするif (c.isLoaded) {
        renderRows(tbody, c.data);
        return;
    }

    c.addChangeListener("isLoaded", function () {
        renderRows(tbody, c.data);
    });
};

// tbodyにrowsで渡されたデータを追加するfunction renderRows(tbody, rows) {var rowsHtml = $.render.personRowsTemplate({ rows: rows });
    $('<div />')
        .html(rowsHtml)
        .contents()
        .appendTo(tbody);
}

myapp.BrowsePersonSet.loadMorePeople_canExecute = function (screen) {// データに続きがある場合は読み込めるreturn screen.PersonSet.canLoadMore;
};
myapp.BrowsePersonSet.loadMorePeople_execute = function (screen) {// データの続きを読み込み、tbodyにデータを追加する
    screen.PersonSet.loadMore().then(function (r) {
        renderRows($('#peopleTable tbody'), r.items);
    });
};

最後の2つのメソッドは、カスタムコントロールの下に置いたボタンの処理で、続きのデータがあったら読み込むといった処理になってます。

最後に、データの続きを読む処理を試すためにPersonSetの取得件数をプロパティから3件に減らしておきます。

実行してみよう

アプリを実行したら、データの読み込みが終わる前に素早くタブ切り替えをしてテーブルを表示してるタブに移動します。そうするとテーブルにデータが3件表示されています。

f:id:okazuki:20130807233735p:plain
続きを読み込むボタンを押すと、続きのデータが読み込まれます。今回はデータを4件しか作ってないので、これ以上データがないのでボタンが消えます。(無効化したら消えるように設定してたんだった)
f:id:okazuki:20130807233933p:plain

まとめ

  • LightSwitchのカスタムコントロールでjQuery mobileのコントロールの実験とかやると面白い。
  • jsRenderはいいテンプレートエンジンだ。
  • LightSwitchは、結構JavaScriptで何でもできそう
  • JavaScriptはインテリセンスあるとはいえC#に比べたら貧弱で辛い

*1:悲しいけど機械翻訳

*2:今度は自作テーマあててみようかな

*3:ここを参考にしました。http://stackoverflow.com/questions/11047670/creating-a-jquery-object-from-a-big-html-string


LightSwitchで手軽に情報を出力したい

$
0
0

LightSwitchの本来の使い方ではないと思われるけど、データなしの画面とかも簡単に作れます。新規作成してBrowse画面を作ってしまえば、あとは画面にボタンを置いたり、カスタムコントロールおいてJavaScriptで好きなもの表示したりとかetc....

ということで、ちょっとした実験をするときの手軽な出力先(コンソールアプリとかみたいなのりで)をいくつか。

王道のconsole

こいつは各ブラウザの開発者ツールのコンソールに出力されます。データなしでBrowseの画面をSampleという名前で作ります。そしてボタンを追加します。
f:id:okazuki:20130810175553j:plain

Write my own methodを選択してメソッドの名前を適当につけます。
f:id:okazuki:20130810175819j:plain

JavaScriptのメソッド名を入れてOK
f:id:okazuki:20130810175819j:plain

画面の右側にメソッドが追加されるので右クリックからEdit Execute codeを選んでボタンを押した時の処理を書きます。
f:id:okazuki:20130810180703j:plain

コードはこんなかんじ。

/// <reference path="../GeneratedArtifacts/viewModel.js" />

myapp.Sample.OutputConsole_execute = function (screen) {// Write code here.
    console.info("Hello world");
};

実行して開発者ツールのコンソールを出した状態でボタンを押すとHello worldと表示されます。

f:id:okazuki:20130810181040j:plain

トーストに出力する

コンソールに出れば十分なんですが、遊び心を持たせたいというときは、トースト通知として出す方法もあります。一度Visual StudioをLogical ViewからFile Viewに変更します。
f:id:okazuki:20130810181235j:plain
この画面でHTMLClientのほうにNuGetでtoastrを追加します。
f:id:okazuki:20130810181414j:plain
toasterを追加したらHTMLClientのdefault.htmにtoastrのcssとjsを追加します。具体的には以下の二行を追加します。cssはheadタグのところに、jsはbodyタグのscriptタグが固まってるあたりにすればいいでしょう。

<linkhref="Content/toastr.css"rel="stylesheet" /><scriptsrc="Scripts/toastr.min.js"></script>

因みにソリューションエクスプローラからtoastr.cssやtoastr.min.jsをdefault.htmを開いているエディタにドラッグアンドドロップしてやれば自動的にコードが吐かれるので、手書きする必要はありません。


次に、ボタンをクリックしたときの処理を書き換えます。Logical Viewに戻ってボタンを押した時の処理のjsファイルを開きます。

インテリセンスを効かせるためにJavaScriptのファイルの先頭にreferenceを追加します。これも、ソリューションエクスプローラからエディタにドラッグアンドドロップでいいのでさくっとやっちゃいましょう。(もう一度File Viewに切り替えないといけないのがめんどくさいですが…)


toastrの使い方はいたって簡単。tostr.info/warning/error/successに文字列を渡すだけです。さくっと書いてみましょう。

/// <reference path="../GeneratedArtifacts/viewModel.js" />/// <reference path="../Scripts/toastr.js" />

myapp.Sample.OutputConsole_execute = function (screen) {// Write code here.
    toastr.info("Hello info");
    toastr.warning("Hello warning");
    toastr.error("Hello error");
    toastr.success("Hello success");
};

実行してボタンを押すと以下のようにトーストが表示されます。
f:id:okazuki:20130810182447j:plain

カラフルで見た目いい感じですね。

まとめ

jsでちょっと遊ぶときの土台としてもLightSwitch便利。これだけ自由度があるってことは、結構つぶしが効くテクノロジかもしれない。

LightSwitchのHTMLClientのサンプルのほとんどでXSSの脆弱性ありそうな気がするんですが…

$
0
0

最近LightSwitchのHTMLClientのサンプルとかコードを色々あさってるんですが、JavaScriptで出力のカスタマイズ自由自在だぜ!!ってところになると以下のような感じのコードをよく見かけます。

/// <reference path="../GeneratedArtifacts/viewModel.js" />

myapp.Browse.ScreenContent_render = function (element, contentItem) {// 仮のデータvar dummyData = { value: 'hoge'};
    $('<h2>' + dummyData.value + '</h2>').appendTo($(element));
};

dummyDataは、本来はcontentItem.valueあたりを使うのですが、今回は簡単な例を示したいだけなのでメソッド内に静的に持たせてます。こんなカスタムコントロールのレンダリング処理のコードをよく見る。んで、実行すると、以下のような感じで、h2タグに囲まれて太く表示できる。
f:id:okazuki:20130810222037j:plain

いやでもvalueにこんな値入ってたらおしまいでしょ・・・と常に感じてる。

/// <reference path="../GeneratedArtifacts/viewModel.js" />

myapp.Browse.ScreenContent_render = function (element, contentItem) {// 仮のデータvar dummyData = { value: 'hoge<script type="text/javascript">alert("Hello XSS!!")</script>'};
    $('<h2>' + dummyData.value + '</h2>').appendTo($(element));
};

実行すると、ありがとうございますXSSです。
f:id:okazuki:20130810222216j:plain

jQueryで書くならこうしとかないとって思うんです。

/// <reference path="../GeneratedArtifacts/viewModel.js" />

myapp.Browse.ScreenContent_render = function (element, contentItem) {// 仮のデータvar dummyData = { value: 'hoge<script type="text/javascript">alert("Hello XSS!!")</script>'};
    $('<h2/>').text(dummyData.value).appendTo($(element));
};

これならvalueに変な値入れられてても平気。
f:id:okazuki:20130810222404j:plain

まとめ

XSSとか基礎すぎて、当然本番では気を付けるよね!?ってノリなのかもしれないけど、こんなノリのサンプルコードだらけなせいでXSSの脆弱性を持ったアプリが量産されないか心配。

追記

もしかしてLightSwitchの世界で閉じてるなら、勝手に変なデータ入れるとエラーにしてくれるとか淡い期待してDBからデータとってくる奴でためしたんですが、ばっちりJavaScript動きました。
f:id:okazuki:20130810223346j:plain

LightSwitchのHTML Clientで画面遷移してみよう

$
0
0

今回は、LightSwitchのLightSwitchらしくない使い方。データを一切作らずに画面の世界だけに閉じた話しです。画面をいくつか作って、画面遷移をしてみたいと思います。試しにプロジェクトを新規作成して、画面を3つ作ります。全部Browse画面にしています。画面名はHome, SecondScreen, LastScreenにしました。
f:id:okazuki:20130811223031j:plain

Homeにボタンを1つ置きます。Write my own codeでNavigateSecondScreenにします。
f:id:okazuki:20130811223231j:plain*1
画面左側にNavigateSecondScreenという項目ができるので右クリックからクリック時の処理を書きます。
f:id:okazuki:20130811223341j:plain
既に定義している画面の場合は、myappというグローバルなアプリケーションを表す変数にshowXXXXというメソッドが定義されているので、それを呼び出せばOKです。引数にbeforeShownとafterClosedというプロパティを持ったオブジェクトを渡せるので、そこで前処理、後処理とかを入れることができます。引数には、それぞれ新しい遷移先の画面のオブジェクトがわたってきます。closedのほうは、どのようなアクションで閉じられたのかを示す値もわたってきます。とりあえず、ログにわたってきた値を出すようにしてみました。

/// <reference path="../GeneratedArtifacts/viewModel.js" />

myapp.Home.NavigateSecondScreen_execute = function (screen) {
    myapp.showSecondScreen({
        beforeShown: function (secondScreen) {
            console.info("navigated: " + secondScreen.details.displayName);
        },
        afterClosed: function (secondScreen, action) {
            console.info("closed: " + secondScreen.details.displayName + ", " + action);
        }});
};

実行すると、Homeにボタンがあるだけの画面が表示されます。
f:id:okazuki:20130811224442j:plain
ボタンを押すとSecond Screenへ遷移します。
f:id:okazuki:20130811224520j:plain
戻るボタンを押すと、Homeに戻ります。

この一連の操作でJavaScriptコンソールに以下の値が出力されます。戻るボタンはキャンセル扱いなんですね。

navigated: Second Screen
closed: Second Screen, cancel

因みに、cancelの部分にはほかにもcommitという値もわたってくることがあります。msls.NavigateBackAction.cancel, msls.NavigateBackAction.commitと===で比較してやればいいと思われます。
f:id:okazuki:20130811224719j:plain


次は、SecondScreenのほうにボタンを置いてNavigateBackというメソッドを実行するようにします。
f:id:okazuki:20130811224907j:plain
ここにmsls.applicationに定義されているnavigateBackメソッドを呼ぶと戻るボタンを押したのと同じことをコードから実行できます。因みに、msls.applicationはmyappでもOKです。myappのほうが楽っぽいです。因みに、ここら辺のmslsの中に定義されている関数やらのリファレンスを見たことがないのがLightSwitchの悲しいところ。

/// <reference path="../GeneratedArtifacts/viewModel.js" />

myapp.SecondScreen.NavigateBack_execute = function (screen) {// 画面左上の戻るボタンと同じっぽい
    myapp.navigateBack();
};

ログには、戻るボタンを押した時と同じようにcancelが表示されます。

navigated: Second Screen
closed: Second Screen, cancel

次は、SecondScreenからLastScreenへの画面遷移処理を追加します。ボタンを置いて遷移処理を書きます。ここらへんは前と同じ手順です。参考にコードだけのせておきます。

myapp.SecondScreen.NavigateLastScreen_execute = function (screen) {
    myapp.showLastScreen();
};

LastScreenにもボタンを1つ置きNavigateHomeというメソッドを呼ぶようにします。クリック時の処理で間のSecondScreenをすっとばして一気にホーム画面に戻るようにします。これもmsls.applicationのnavigateHomeメソッドを呼ぶだけでOKです。(myappでもOK)

/// <reference path="../GeneratedArtifacts/viewModel.js" />


myapp.LastScreen.NavigateHome_execute = function (screen) {
    myapp.navigateHome();
};

実行してログを確認します。Home -> SecondScreen -> LastScreen -> Homeの順番に遷移するようにオペレーションをすると以下のようなログが出てきます。

navigated: Second Screen
closed: Second Screen, cancel

ログは変わりません。closedのログが出るタイミングがSecondScreenからLastScreenに遷移するところではなくLastScreenからHomeに戻るタイミングで出力される点がポイントです。どうも、LastScreenに遷移したタイミングでは、SecondScreenはまだ生きてるっぽいです。

データが伴う場合

さて、今回のサンプルはデータが伴わないやつでしたが、LightSwitchの一般的なアプリではデータをがしがし編集したりする画面が結構あります。そういうときには以下のメソッドを使ったりするので頭に入れておくといいかも

  • myapp.commitChanges()
    • データの変更を反映して画面を戻る。このとき、afterClosedにはcommitが渡ってくる。
  • myapp.applyChanges()
    • データの変更を反映するだけで画面遷移はしない。applyChanges -> navigateBackをした場合のafterClosedにはcancelが渡ってくる点は要注意。試す前はcommitが渡ってくると思ってた。
  • myapp.cancelChanges()
    • データの変更を破棄して画面を戻る。このとき、afterClosedにはcancelが渡ってくる。

まとめ

リファレンスマニュアルをMSさん早く作ってくださいお願いします。

*1:スクリーンショットがLastScreenのになってますがHomeだと思ってください…

HTMLClientでデータバインドしてみた

$
0
0

LightSwitchにはデータバインディングの仕組みがあります。ちょっと試してみました。
画面にString型のInputTextというプロパティを追加した状態で、InputTextを2つ画面に置きます。画面に置いたInputTextは、2つともカスタムコントロールに変更します。
f:id:okazuki:20130815124206j:plain

カスタムコントロールのレンダリング処理を以下のようにします。contentItemのdataBindというメソッドがデータバインディングをするためのメソッドになります。ここの第一引数で指定したパス(contentItemのプロパティ)が変更されたら、コールバックが呼び出されます。コールバックの引数に新しい値がわたってくるので、画面に反映してやります。
データバインドというか、原始的な変更通知の仕組みっぽいですね。

ということで、1つを<input type="text" />で入力可能な項目に、もう1つをで出力用の項目にしてみました。<input type="text" />のほうはchangeを使ってテキストボックスの中身が変わったタイミングでcontentItem.valueに値をつっこんでいます。

なかなか、直感的じゃないなと思うのはcontentItemのvalueが、ここでは画面につくったInputTextのプロパティになってるみたいです。ということでコードは以下のようになります。

myapp.Home.InputText_render = function (element, contentItem) {var input = $('<input type="text" />');
    input.appendTo($(element));

    contentItem.dataBind('value', function (value) {
        input.val(value);
    });
    input.change(function () {
        contentItem.value = input.val();
    });
};

myapp.Home.InputText1_render = function (element, contentItem) {var output = $('<span />');
    output.appendTo($(element));

    contentItem.dataBind('value', function (value) {
        output.text(value);
    });
};

あとは、画面のcreatedに値の初期化処理を追加するのと、おまけでボタンを画面に1つおいて押したときにも、InputTextの値を書き換える処理を追加してみました。

myapp.Home.created = function (screen) {
    screen.InputText = 'Hello world';
};
myapp.Home.ChangeValue_execute = function (screen) {
    screen.InputText = '変更した';
};

実行するとこんな感じに動きます。

まずは初期状態。createdでHello worldをInputTextに設定してるのが、表示にも反映されています。
f:id:okazuki:20130815124832j:plain

そして次にChange valueボタンを押したとき。ちゃんとボタンを押した処理で設定した値が見た目に反映されています。
f:id:okazuki:20130815124924j:plain

そして、テキストボックスに文字列を入力してフォーカスを外してみたとき。
f:id:okazuki:20130815125004j:plain

ばっちり動きますね。

ということで、LightSwitchのHTMLClientでのデータバインドの基本的な使い方でした。

GridViewでパララックススクロールのような効果を持たせる方法

$
0
0

コードレシピにサンプルコードをアップしました。
まぁ場当たり的に作っていけばこの方法でも結構綺麗なの出来そうな気がします。

汎用性を持たせるなら、時間以外のものをもとにアニメーションを組み立てられるストーリーボードみたいなものを作らないといけないのかなぁ。既に誰か作ってないかな。

GridViewでパララックススクロールのような効果を持たせる方法

VAIO Duo 11の光学式イボを快適に使う方法

$
0
0

VAIO Duo 11のキーボードの真ん中についてる光学式のポインティングデバイスですが、こいつデフォルトだとタッチするとクリックだと判定してくれます。これが、かなり感度がよすぎて誤動作してしまうので使ってませんでした。

先日、修理に出して綺麗になってかえってきたのをきっかけに設定をみなおしてたら、真ん中のいぼをタッチしたときにクリックする設定って切れるんですね。下の画像の赤いぶぶんのチェックを外せばOK。
f:id:okazuki:20130815204705p:plain

因みに上の画面には、コンパネのマウスのところからいけます。これで快適VAIO Duo 11ライフを!

LightSwitchのHTML Clientで時間のかかる処理をやる方法+その間プログレスリングを出す方法

$
0
0

LightSwitchのHTML Clientのリファレンスがほしいと思う今日この頃です。今日は、時間のかかる処理をやる方法と、その間にプログレスリングを出す方法をちょろっとやってみました。
とりあえず、時間のかかる処理はPromiseというやつを使うみたいです。どんなものかというとここら辺を見てみるといいかも?

上のリンクは二年くらい前の記事になるので古いかも。LightSwitchにはWinJS.Promiseというのがあるのから察するにWindows ストア アプリあたりからここらへんの実装もってきてそうなので下のリンクのほうが参考になりそう。

やってみよう

とりあえず5秒くらいかかる処理をやってみようと思います。5秒かかる処理はsetTimeoutで簡単に実装してみました。ボタンクリックのときの処理に以下のような感じのコードを書きます。

myapp.Browse.ShowProgress_execute = function (screen) {// promiseOperationで時間のかかる処理を開始する
    msls.promiseOperation(function (op) {
        setTimeout(function () {// コールバックの引数のcompleteを呼ぶと処理完了// 0-100くらいの値を結果として返す
            op.complete(Math.random() * 100);
        }, 5000);
    }).then(function (result) {// 後続の処理はthenで繋げる。引数にcompleteで渡した引数が入ってる。
        msls.showMessageBox(result);
    });
};

ボタンを押して5秒くらいたつとメッセージボックスにランダムな数字が表示されます。
f:id:okazuki:20130816123155j:plain
お手軽ですね。

処理中であることを伝えたい

ということで、時間のかかる処理をやってるのはいいのですが処理してる間何もユーザーにフィードバックがありません。ということで処理中であることを表すプログレスリングを表示する方法をやってみました。
これはmsls.showProgressという、ズバリなメソッドがあって、この引数にPromiseを渡してやれば、Promiseの処理が終わるまでの間画面をブロックしてプログレスリングを出してくれます。
ということで、さっきの処理に追加するとこんな感じです。

myapp.Browse.ShowProgress_execute = function (screen) {var promise = msls.promiseOperation(function (op) {
        setTimeout(function () {// 0-100くらいの値を結果として返す
            op.complete(Math.random() * 100);
        }, 5000);
    }).then(function (result) {
        msls.showMessageBox(result);
    });
    // プログレスリングっぽいのだして
    msls.showProgress(promise);
};

こうすると5秒間以下のような感じの画面になります。
f:id:okazuki:20130816123652j:plain


邪魔なものは閉じれるようにしたい

$
0
0

LightSwitchはjQueryとjQueryMobile使ってるのでやる気になればなんだってできます。そんな例の1つとして開閉式コンテンツを試してみました。

列のレイアウトのグループの中に、ボタンがたくさんあるグループを用意しました。
f:id:okazuki:20130816123935j:plain
ボタンがたくさんあって邪魔なので開閉式にしてみます。この図の中のGroup1のレンダリング後の処理を書くためにプロパティのPostRenderコードの編集を選択します。
f:id:okazuki:20130816124114j:plain
jQuery Mobileの開閉式コンテンツはこちらのサイトを参考にしました。

とりあえずdivにdata-role="collapsible"をつけて、div直下に見出しタグを置けばいいみたいです。ということで、PostRenderコードの中は以下のような感じになります。

myapp.Browse.Group1_postRender = function (element, contentItem) {// 必要な属性を追加var $element = $(element);
    $element.attr({'data-role': 'collapsible',
        'data-collapsed': 'true'});
    // コンテナの先頭に見出しタグを挿入
    $('<h2 />').text('メニュー').prependTo($element);
};

実行すると以下のように、最初は閉じてる雰囲気のメニューというボタンが置いてあるだけの状態になります。
f:id:okazuki:20130816124533j:plain

もちろん展開できます。
f:id:okazuki:20130816124616j:plain

見た目は、テーマを変えたりしてお好みにできるので今回は気にしないでおこう。

MSDN SubscriptionのOfficeはAzureの仮想マシンには入れないほうがいい?

$
0
0

ちょっと「ん?」って思うことがあったのでメモ。間違ってる内容があったら指摘お願いします。
先日MSDN Subscriptionのソフトウェアの使用権が変わって、Windows Azure バーチャルマシンでもMSDNで提供されるソフトウェアが使えるようになりました。

2013 年 6 月 1 日より、サブスクリプションをアクティブ化された MSDN サブスクリプション会員の方には、MSDN ソフトウェア (Windows および Windows Server を除きます) を Windows Azure バーチャル マシンで実行するためのライセンスが付与されるため、アプリケーションをより柔軟に開発およびテストできるようになります。

引用元: http://msdn.microsoft.com/ja-jp/subscriptions/cc150618.aspx

なので、Office 2013を入れて使ってました。因みに、Officeに関しては以下のような例外的な扱いもあります。

Office の一般業務用ライセンスについて

MSDN Subscription で提供するソフトウェアは、開発者ライセンスに基づき提供されています。開発者ライセンスでは、開発、テスト及びデモンストレーション目的でのみご利用いただけます。

ただし、Visual Studio 2010 Ultimate with MSDN ならびに Visual Studio 2010 Premium with MSDN でご提供している Microsoft Office 製品については、一般業務用として 1 部を一般業務に使用できます。ただし、Microsoft Office 製品を使用できるのは、適切な MSDN ライセンスを保有するユーザー 1 名に限られます。

引用元: http://msdn.microsoft.com/ja-jp/subscriptions/dd179300.aspx

そんなOffice 2013ですが、たまにライセンス認証を行っているのに、ライセンス認証が必要ですと表示されることがちょくちょくあり、先日は電話でオペレーターの方に対応してもらってライセンス認証を行うようなことがありました。
そして、今日もOfficeを起動してみたら、ライセンス認証が必要ですという通知が・・・。また電話でアクティベーションしてもらおうと思ったらライセンスキーにロックがかかってるからMSDN Subscriptionの窓口に連絡する旨を伝えられたので電話して確認したところ、アクティベーションの上限に達してるのでロックがっかってるのでこれ以上は使えませんという回答をいただきました。

恐らく以下のようなことが起きてると認識しています…。

  • Windows Azureのバーチャルマシンは、ハードウェア障害で物理マシンを移動したタイミングでOfficeが別マシンに入ったと判断してライセンス認証をしろと通知してくる。
  • ライセンス認証を行っていくと、そのうちそのプロダクトキーはロックされる。
  • ロックは解除してもらえない。

Windows Azureの仮想マシンにインストールして使っていいというライセンスになっても、仮想マシンに入れてると、割とすぐにプロダクトキーがロックされるので、すべてのプロダクトキーをすぐに使い切ってしまうのではないか?とう問いに対しては「プロダクトキーを入れなくても一定期間は体験版として使えるのでそうしてください」とのこと…。それMSDNじゃなくても一緒じゃない?

以下のようなことも書いてあるけど追加の要求とかって窓口では取り合ってもくれないのかな・・・。

サブスクリプションで利用可能なすべてのプロダクト キーを要求し、利用できるすべてのライセンス認証を使い果たした場合は、最寄りの MSDN カスタマー サービス センターに連絡して追加のキーを要求できます。 追加の要求については、個々の状況に応じて承認の可否が検討されます。 承認された場合は、サブスクライバー ダウンロード ページからプロダクト キーにアクセスできます。

引用元: http://msdn.microsoft.com/ja-jp/subscriptions/cc137104.aspx


とりあえず、ハードが変わるとアクティベーションが無効になる製品はMSDNサブスクリプションのプロダクトキーをすぐに使い切ってしまう可能性が高いので入れないほうが現状は賢明っぽい。ということでした。

ここ数日の悩み

$
0
0

LightSwitchでフォーム認証を有効にしたときに、デバッグ時は勝手にテストユーザーでログインした状態になってしまう。
これを無効にしたまま、デバッグ実行する方法を知りたい…。

非同期処理でWindowのClosingをキャンセルするかどうか決めたい

$
0
0

お昼にこんな話題が…。

もんもんと考えた結果以下のようなBehaviorが出来ました。実用に耐えうるか…?

using System;
using System.ComponentModel;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Interactivity;

namespace WpfApplication4
{
    publicclass AsyncClosingBehavior : Behavior<Window>
    {
        // ClosingAsyncActionにnullが設定された場合に使用する値privatestaticreadonly Func<Task<bool>> FalseAction = () => Task.FromResult(false);

        // closingをCancelするかどうかprivatebool cancelClosing = true;
        // 現在closingイベントの処理中かどうかprivatebool processing;

        /// <summary>/// WindowのClosingイベントでキャンセルするかどうかを確認するための非同期処理を行うデリゲート/// </summary>public Func<Task<bool>> ClosingAsyncAction
        {
            get { return (Func<Task<bool>>)GetValue(ClosingAsyncActionProperty); }
            set { SetValue(ClosingAsyncActionProperty, value); }
        }

        publicstaticreadonly DependencyProperty ClosingAsyncActionProperty =
            DependencyProperty.Register(
                "ClosingAsyncAction",
                typeof(Func<Task<bool>>),
                typeof(AsyncClosingBehavior),
                new PropertyMetadata(FalseAction, null, CoerceClosingAsyncAction));

        // nullだったらFalseActionprivatestaticobject CoerceClosingAsyncAction(DependencyObject d, object baseValue)
        {
            return baseValue ?? FalseAction;
        }

        protectedoverridevoid OnAttached()
        {
            base.OnAttached();
            this.AssociatedObject.Closing += this.WindowClosing;
        }

        protectedoverridevoid OnDetaching()
        {
            this.Cleanup();
            base.OnDetaching();
        }

        // イベントの後片付けprivatevoid Cleanup()
        {
            this.AssociatedObject.Closing -= this.WindowClosing;
        }

        private async void WindowClosing(object sender, CancelEventArgs e)
        {
            e.Cancel = this.cancelClosing;
            
            // Windowを閉じる場合は何もしないif (!this.cancelClosing)
            {
                return;
            }
            // Closingの処理中の場合は何もしないif (this.processing)
            {
                return;
            }

            this.processing = true;
            // Closingイベント中にCloseすると例外が出るので一旦Closingイベントを確実に抜けて続きをやる
            await this.Dispatcher.InvokeAsync(async () =>
            {
                try
                {
                    // 非同期呼び出しでクローズをキャンセルするかどうか問い合わせるthis.cancelClosing = await this.ClosingAsyncAction();
                    if (!this.cancelClosing)
                    {
                        // キャンセルしない場合は閉じるthis.Cleanup();
                        this.AssociatedObject.Close();
                    }
                }
                finally
                {
                    this.processing = false;
                }
            });
        }
    }
}

使う側はこんな風にTaskを返すメソッドを定義して、それをFunc>で返すプロパティを定義しておきます。

using System;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;

namespace WpfApplication4
{
    /// <summary>/// MainWindow.xaml の相互作用ロジック/// </summary>publicpartialclass MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        public Func<Task<bool>> ClosingAsyncAction
        {
            get { returnthis.ClosingAsync; }
        }

        private Task<bool> ClosingAsync()
        {
            var currentContent = this.Content;

            var source = new TaskCompletionSource<bool>();
            var panel = new StackPanel();
            var confirmMessage = new TextBlock { Text = "本当に閉じるの?" };
            panel.Children.Add(confirmMessage);

            var ok = new Button { Content = "OK" };
            var cancel = new Button { Content = "Cancel" };
            panel.Children.Add(ok);
            panel.Children.Add(cancel);

            ok.Click += (_, __) =>
            {
                this.Content = currentContent;
                source.SetResult(false);
            };
            cancel.Click += (_, __) =>
            {
                this.Content = currentContent;
                source.SetResult(true);
            };

            this.Content = panel;
            return source.Task;
        }
    }
}

んで、Windowにビヘイビアをこんな風においておきます。

<Windowxmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"xmlns:local="clr-namespace:WpfApplication4"x:Class="WpfApplication4.MainWindow"Title="MainWindow"Height="350"Width="525"Name="window"><i:Interaction.Behaviors><local:AsyncClosingBehavior ClosingAsyncAction="{Binding ClosingAsyncAction, ElementName=window}"/></i:Interaction.Behaviors><Grid><TextBlock HorizontalAlignment="Left"Margin="43,39,0,0"TextWrapping="Wrap"VerticalAlignment="Top"><Run Language="ja-jp"Text="着任"/></TextBlock></Grid></Window>

実行するとこんな感じ。
f:id:okazuki:20130822215123j:plain
Windowを閉じようとするとこんな風になって
f:id:okazuki:20130822215201j:plain
キャンセルすると閉じない。
f:id:okazuki:20130822215236j:plain
OKすると、もちろん閉じる。


なんか、まだまだ良くできそうでもんもんとしてる上に実用するのか?と言われるとなんとなく自分ではしないような気がしつつメモ。

Blendのデータストア

$
0
0

Blendにはデータのところからデータストアというものを作れます。
f:id:okazuki:20130822225859j:plain
こいつは、プロパティを定義しておいたり、XAMLからプロパティの初期値を設定できたり、Behaviorから値をセットしたりとかBindして色々やったりするのに使うと割と便利だとBlend使いの人達の間では有名?な奴です。ブラックボックスのまま使うのも気持ち悪いので、ちょっとデータストアを作ったときに生成されるコードをちょっと追いかけてみたのでメモっておきます。

データストアの定義先による違い

データストアを作成するときに、データストアの定義先を2つ選ぶことができます。

  • プロジェクト
  • このドキュメント

f:id:okazuki:20130822230400j:plain

プロジェクト

プロジェクトを選ぶと、App.xamlのResourcesにデータストアが定義されます。HogeDataStoreをプロジェクトに対して作成した後にApp.xamlを見ると以下のようになっています。

<Applicationxmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:DataStore="clr-namespace:Expression.Blend.DataStore.HogeDataStore"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"mc:Ignorable="d"x:Class="DataStoreEdu.App"StartupUri="MainWindow.xaml"><Application.Resources><DataStore:HogeDataStore x:Key="HogeDataStore"d:IsDataSource="True"/></Application.Resources></Application>
このドキュメント

このドキュメントを選ぶとデータストアを作成したときに開いていたウィンドウやユーザコントロールなどのXAMLのResourcesに定義が追加されます。FugaDataSourceを、MainWindow.xamlを開いた状態で、このドキュメントに対して作成したあとにMainWindow.xamlを見ると以下のような定義が追加されています。

<Windowxmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:DataStore="clr-namespace:Expression.Blend.DataStore.FugaDataStore"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"mc:Ignorable="d"x:Class="DataStoreEdu.MainWindow"Title="MainWindow"Height="350"Width="525"><Window.Resources><DataStore:FugaDataStore x:Key="FugaDataStore"d:IsDataSource="True"/></Window.Resources><Grid/></Window>
定義先による違いのまとめ

以上のことから、定義先の違いによって、XAMLのStaticResourceを使って参照できる範囲が以下のように異なることがわかります。

  • プロジェクト
    • App.xamlに定義されているのでアプリケーション全体から参照可能
  • このドキュメント
    • WindowなどのResourcesに定義されているので、そのXAML内からしか参照できない

データストアのコード

定義先の違いによる違いはわかったので、次はデータストアのコードを眺めてみます。データストアのコード自体は、定義先が違っても変わらないので今回は最初に作成したHogeDataStoreのコードを見ていきます。

コードの場所

データストアを作成すると、プロジェクト直下にDataStoreという名前のフォルダが作成されます。そしてDataStoreの中に作成したデータストアの名前のフォルダが作られていて、その中にxamlとxaml.csとxsdという3つのファイルが作成されています。
f:id:okazuki:20130822231259j:plain
1つのデータストアを作成するとプロジェクトに以下の2つのクラスが作成されていることがソリューションエクスプローラから読み取れます。

  • HogeDataStoreGlobalStorage
  • HogeDataStore

このデータストアのクラスの名前空間は、プロジェクトとは関係なくExpression.Blend.DataStore.データストア名という命名規約で名前がついているみたいです。なんか、名前区間かぶりそうで嫌な感じです。

生成されるクラスの中身

データストアとして作成されるクラスは、2つしかありませんが、この2つのクラスが複雑に絡み合ってるのでちょっとコードを読み解くのがしんどいです。大体以下のような感じになります。

HogeDataStoreGlobalStorageクラス

Singletonというstaticなプロパティがあり、Singletonで取得したインスタンスに対して、データストアに定義したプロパティにアクセスすることができます。例えば、HogeDataStoreにProperty1というプロパティが定義されている場合は以下のようなコードでプロパティにアクセス可能です。

// 設定
HogeDataStoreGlobalStorage.Singleton.Property1 = "ほげ";
// 取得
var hoge = HogeDataStoreGlobalStorage.Singleton.Property1;

とってもグローバルで嫌な感じですので、多用は危険そうです。

HogeDataStoreクラス

HogeDataStoreGlobalStorageはシングルトンな感じなので、じゃぁHogeDataStoreなら…!と期待するところですが、このクラスは、HogeDataStoreGlobalStorageに処理を丸投げしてるだけなので、インスタンスを何個作ってもあまりいいことはありません…。例えばProperty1というプロパティのコードは以下のように丸投げコードになっています。

privatestring _Property1 = string.Empty;

publicstring Property1
{
	get
	{
		return HogeDataStoreGlobalStorage.Singleton.Property1;
	}

	set
	{
		HogeDataStoreGlobalStorage.Singleton.Property1 = value;
	}
}

しかも、こいつのコンストラクタではHogeDataStore.xamlから値を読み込んでデータの初期化とかをやってるので、newするだけでHogeDataStoreGlobalStoregaの中身がリセットされてしまいます。超危険です。コンストラクタのコードを以下に示します。

public HogeDataStore()
{
	try
	{
		System.Uri resourceUri = new System.Uri("/DataStoreEdu;component/DataStore/HogeDataStore/HogeDataStore.xaml", System.UriKind.Relative);
		if (System.Windows.Application.GetResourceStream(resourceUri) != null)
		{
			HogeDataStoreGlobalStorage.Singleton.Loading = true;
			System.Windows.Application.LoadComponent(this, resourceUri);
			HogeDataStoreGlobalStorage.Singleton.Loading = false;
			HogeDataStoreGlobalStorage.Singleton.Register(this);
		}
	}
	catch (System.Exception)
	{
	}
}

因みにXAMLはデフォルトではこんな感じになってます。値を設定してるだけですね。

<DataStore:HogeDataStore xmlns:DataStore="clr-namespace:Expression.Blend.DataStore.HogeDataStore"Property1="値"/>

実際にリセットされるのか試してみました。

// 値を設定しても
HogeDataStoreGlobalStorage.Singleton.Property1 = "ほげ";
// HogeDataStoreのインスタンスを作成すると…
var store = new HogeDataStore();
// リセットされちゃう
MessageBox.Show(HogeDataStoreGlobalStorage.Singleton.Property1);

このメソッドを実行すると、以下のように"値"と表示されました。
f:id:okazuki:20130822233301j:plain

この挙動は、おそらくWindowのインスタンスが生成されたタイミングで、Windowに定義されてるデータストアの値をリセットするためのものだと思われます。そのため、同じWindowを複数表示するとデータストアのデータが意図せぬタイミングでリセットされます。同じWindowを複数表示するようなアプリケーションでは利用を控えたほうが幸せそうです。

まとめ

ということで、データストアを使うときは以下のように使うといいでしょう。

  • "このドキュメント"を選択する場合はそのWindowが同時に複数表示されないようにすること
  • コードからDataStoreをnewしないこと
  • コードからDataStoreのデータにアクセスするときはHogeDataStoreGlobalStorage.Singletonを通じてアクセスすること

ということになります。そもそも単一ページしか表示されないようなWindows PhoneアプリやWindowsストアアプリでは、同時に同じページが表示されることなんてないのでnewさえしなければ問題ないと思います。だが、Windows ストアアプリにはデータストアがなかった…!!

Viewing all 1387 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>