ListBoxのアイテムを追加/削除するときにアニメーションさせるためのコントロールを作ってみた

どこかの投稿サイトで、
ListBox コントロールに動的にアイテムを追加したとき、
アニメーションするようにしたいけどどうすればいいの?
みたいな質問が飛んでいて、
こうやったらできるんじゃないかな~と思っていたものを
実際に組んでみたので紹介しようと思います。

完成品はこちら。
test

ListBox コントロールなどの ItemsControl 派生のコントロールは、
指定されたアイテムを並べるとき、
コンテナと呼ばれるコントロールに各アイテムを入れて表示しています。
ここでは、そのコンテナをカスタムコントロールにして、
そのコントロール内でアニメーション処理させます。

というわけでカスタムコントロール AnimatedContainer クラスを作ります。

ほぼ自動生成されたコードのままですが、
Border コントロールの中に Button をひとつと、
指定されたコンテンツを表示させるための ContentPresenter を置いてあります。
非常に雑な置き方ですが、
このカスタムコントロールの配置はなんでもいいです。
というのは、実際の配置はこのカスタムコントロールを使う側で
Template を指定してユーザ側で指定してもらうからです。

さておき、
コードビハインドを見てみましょう。

いきなり長いコードですが、
ポイントはサイズ変更イベントハンドラの OnSizeChanged メソッドで
このコントロールが表示されるときにフェードインさせるアニメーションを実行しています。

また、PART_DeleteButton と名付けられたボタンがクリックされたタイミングで
このコントロールを非表示とするようにフェードアウトさせるアニメーションを実行しています。
さらに、フェードアウトのアニメーションが終了したら
コールバックとして DeletedCommand プロパティに指定されたコマンドを実行するようにしています。

ListBox コントロールにアイテムを追加/削除することを考えてみましょう。
追加するときはとにかく Add すればコンテナがひとつ増え、
始めに OnSizeChanged が呼ばれることになります。
では、逆に削除するときはどうでしょうか。
いきなり ItemsSource のコレクションから Remove などで削除してしまうと、
フェードアウトさせたいコンテナ自体がいきなり消えてしまいます。
したがって、コレクションから削除する前にフェードアウトのアニメーションを実行し、
そのアニメーションが完了してからコレクションから削除しなければいけません。
そんなわけで、削除するときは DeleteCommand プロパティを利用して
コレクションからアイテムを Remove すればいいのです。
また、そのようにできるように上記のコードでは、
DeleteCommand.Execute(this.DataContext) のように、
AnimatedContainer コントロールの DataContext を
パラメータとしてコマンドを実行しています。
これで処理を渡された方はどのアイテムを削除すれば良いかが判断できるようになっています。

そんなわけでこのカスタムコントロールを使う側の XAML と ViewModel です。

念のため ICommand インターフェースを実装した DelegateCommand クラスのソースも。

今回は ListBox コントロールを対象としましたが、
他の ItemsControl クラス派生のコントロール、
例えば TreeView とかDataGrid とかでも
応用が利くんじゃないかなぁと思っています。

アニメーションは凝ると楽しいけど、
実用的なものを考えようとすると難しいなぁ。
というわけで今日はこの辺で。

記事一覧を追加

久しぶりの投稿ですが、
ようやく全記事の一覧を表示するようにしました。
これでちょっとは見やすいサイトになってきたか。
後はもっとネタを投下して充実させていかなければ。

TabControl でコンテンツ切替確認ダイアログを表示させる

とある投稿サイトで表題の要求を見かけたので、
せっかくなのでサンプルコードを作ってみました。
まあ、やってやれなくはないということです。

方針は次の通り。

  1. TabControl.ItemsSource には ViewModel のコレクションを指定する
  2. TabControl.ItemsTemplate で TabItem のヘッダ部の外観を指定する
  3. ダイアログ表示は添付ビヘイビアで実現する
  4. TabControl.SelectedIndex とデータバインドし、変更があったらいったん元に戻す
  5. 確認ダイアログで OK が選択されたら改めて SelectedIndex を変更する

というわけでサンプルのファイル構成はこんな感じ。

NotificationObject クラスは INotifyPropertyChanged を実装した ViewModel などの基底クラス。
Content1ViewModel などが TabControl で切り替えられる対象となる ViewModel たち。
それらに対する View が Content1View などになります。
そして DialogBehavior クラスで添付プロパティを定義し、
この中で確認ダイアログを表示するようにしています。

DialogBehavior クラスは以下の添付プロパティを持っています。

添付プロパティ名 内容
 Message string  ダイアログに表示するメッセージを指定します。
 Caption string  ダイアログのキャプションを指定します。
 Callback Action<bool>  ダイアログのコールバック処理を指定します。

サンプルを実行するとこのような画面が表示されます。

クリップボード03

そして、タブを切り替えようとすると確認ダイアログが表示されます。

クリップボード04

OK を押すと初めて画面が切り替わります。

クリップボード05

ちなみに、
SelectedIndex が変更されたことを受け取ってから
いったん元の値に戻しているので、
View の Loaded イベントなんかは走ってるんじゃないかな~と思い、
Loaded イベントで出力ウィンドウに出力するようにしかけておいたんですが、
これが走っていませんでした。
この辺がなんとなく気持ち悪い感じがしなくもないですが、
そういった機微は問題にぶち当たってから考えましょ。

というわけでおしまい。

GitHub 始めました

前回紹介したコントロールライブラリですが、
GitHub で現在再構築中です。
まだ数は少ないですが、いずれはグラフコントロールを含めて
すべてを再構築すべく日々更新しています。

再構築している理由は
自分の勉強不足のためまともに動作しない部分が散見されるためです。
その修正も含めての再構築なのでちょっと時間がかかっています。
再構築というか、ゼロから開発し直しているような状態なので、
以前とはプロパティ名が違うものもあるという
互換性無視な感じで好き勝手やっています。
まあどうせ誰も使ってないだろうしいいだろーってことで。

現在は開発作業をそのままプッシュしていることもあるので
どこかにバグも潜んでいるかもしれないことを加えておきます。
どこかのタイミングでリリースバージョンとし、
それ以降はローカルで開発作業をおこなうようにしたいと思っています。

政府統計データ取得 API e-Stat の簡単な使用方法 その 4

今回はいよいよ統計データ取得です。

前回までのコードで次のような出力ができるようになりました。
ScreenShot03

前回までの実行結果から、
政府統計コードが 00200524 である人口推計の
2012 年に調査したデータで、
“年齢(各歳),男女別人口及び人口性比-総人口,日本人人口” という統計表に対する
統計表 ID が “0003080162” で、
それに対する絞込条件は、

cat01:男女別・性比較
cat02:人口
cat03:年齢各歳
area:全国
time:時間軸(年月日現在)

であることがわかりました。
今回はこれらの情報を基に、
条件を絞り込んで統計データを取得したいと思います。

統計データ取得のリクエスト URL は次のようになります。

このリクエスト URL に対して、
さらに絞込条件に関するパラメータを追加することで、
取得したい統計データのみを取得できます。

さて、
ここで取得したいデータを、
各歳それぞれの男性の人口および女性の人口であるとします。
また、ここでの人口は日本人人口とします。

男性の人口と女性の人口をそれぞれ取得したいため、
絞込条件 cat01 に対する条件は “男” または “女” になります。
それぞれの code は “002” と “003” となります。
このように絞込条件が複数ある場合はカンマ区切りで指定します。
パラメータは次のようになります。

次に、日本人人口の値を取得したいため、
絞込条件 cat02 に対する条件は “日本人人口” となります。
code は “002” となります。
パラメータは次のようになります。

最後に、
各歳それぞれの人口を知りたいため、
絞込条件 cat03 に対する条件は “0歳”、”1歳”、・・・、”99歳”、”100歳以上” となります。
絞込条件が複数であるため、
cat01 と同様にすると次のようになります。

項目数が 101 個もあるため、入力が非常に大変ですね。
さらに、仕様書を確認すると、
ひとつの絞込条件に対する項目数は 100 個までだそうです。
したがって、このままでは上限を超えているため、
統計データを取得することができません。
このような場合は、パラメータの指定方法として、
“cdCat03″ ではなく、”cdCat03From” と “cdCat03To” を使用します。
絞込条件の開始条件として、”cdCat03From” を使用し、
絞込条件の終了条件として、”cdCat03To” を使用します。
今回の場合は “0歳” から “100歳以上” までが絞込条件となるため、
cdCat03 パラメータはつぎのようになります。

以上、今回の例では、
統計データ取得のためのリクエスト URL は次のようになります。

これまでの絞込条件によるパラメータをすべて “&” でつなげて結合した形となります。

それでは C# コードから統計データ取得を実行してみましょう。
今回のコードは次のようになります。

前回と同様、Json クラスや GetValue() 拡張メソッド等は省略しています。

統計データ取得のリクエストに対するレスポンスは、
GET_STATS_DATA をルートタグとして、
GET_STATS_DATA/STATISTICAL_DATA/DATA_INF/VALUE に具体的な値が格納されます。
本当は、指定した絞込条件によって本当にデータが取得できたかどうかなどを調べ、
その上で VALUE タグにアクセスするべきですが、
今回は前回までのコードから明らかにデータがあるとわかっているため、
その辺の異常検出コードのほとんどを省略しています。

実行結果は次のようになります。
ScreenShot04

絞り込んだ条件にヒットしたデータだけを取得していることが確認できると思います。
試しに cat03 に対する条件をひとつだけにしてみたり、
いろいろいじってみるともっと理解できると思います。
また、VALUE タグには上記コードの他にも、unit 属性があったり、
いろいろここでは省略されているものがあるので、
仕様書とにらめっこしながらいじってみて下さい。

実際のアプリケーションに実装するには、
コードとそれに対する表題を結び付けたり、
そもそも政府統計コードを用意しておかなきゃいけなかったり、
いろいろ表示のためのデータ変換やら前準備がたくさんあります。

以上、政府統計データ取得 API の簡単な使用方法でした。
果たして本当に簡単だったのだろうか…。

政府統計データ取得 API e-Stat の簡単な使用方法 その 3

前回までのおさらい。
統計データを取得するには、
統計表情報取得によって得られる “統計表 ID ” と、
メタ情報取得によって得られる “項目コード” が必要でした。

統計表情報によって “統計表 ID” を得ることに成功したのが前回です。
今回はこの “統計表 ID” を使って、
その統計表に対するメタ情報を取得します。

メタ情報取得のリクエスト URL はつぎのようになります。

というわけで前回までのコードに追加する形で、
コード全体は次のようになります。

45 行目以降が今回追加したコードです。
前回までで取得した統計表に関するデータの一番最初の統計表 ID を使用するようにして、
メタ情報取得に関するコードを追加しています。
Json クラスや GetValue() 拡張メソッド等に関するコードは今回省略しています。
詳細は前回までの記事を確認して下さい。

実行結果は次のようになります。
ScreenShot02

CLASS_OBJ タグが、統計表に対する統計データの絞込条件となり、
統計データによってその数が異なります。
今回の例に示す、統計表 ID 0003080162 に対する統計データの絞込条件として、
cat01、cat02、cat03、area、time という条件があるということがわかりました。

しかし、例えば cat01 の “男女別・性比” で絞り込もうとしたとき、
どのような値があるのかがまだわかりません。
実は、それぞれの絞込条件 CLASS_OBJ の中にさらに CLASS タグがあり、
これが絞込条件の詳細情報となります。

というわけで CLASS_OBJ タグの中の CLASS タグも表示するように改良します。
先ほどのコードの 61 行目から始まる foreach 文の中を次のように変更します。

それぞれの CLASS_OBJ タグの中に CLASS タグが存在するので、
foreach 文の中で CLASS タグを探索するコードを書いています。
そして、CLASS タグは複数存在する場合もあるので、
基本的に object[] で取得するようにしています。
さらに foreach 文を書いて、すべての CLASS タグの中の
code および name 属性の中身をコンソール上に表示させています。
外側の foreach 文で出力しているコンソール文字列と区別がつくように、
内側の foreach 文でコンソールに出力するときは先頭に “\t” を付けることで、
インデントを追加しています。

出力結果はこちらになります。
ScreenShot03
縦長な画像ですが、実際はスクロールして確認できると思います。

これで晴れてすべての絞込条件の表題と詳細を把握することができました。
後はこれらの条件を組み合わせて
統計データ取得をおこなうだけです。

というわけで次回はいよいよ統計データ取得です。