#wp7dev_jp

Windows Phone ATND 24 Version

MSDNにはパフォーマンスについての記事があります。実はプログラミング Windows Phone の最後にも書きたかったけど、かけなくて、箇条書きしかできなかったのでそれを描こうと思っていました。が....

なんと自分の番が回ってくる前にMSDNが日本語化されそのままいいドキュメントになってしまいました。

Windows Phone 用アプリケーションのパフォーマンスに関する考慮事項

そんなわけで、わたしは手を抜いてこのまとめ+これまでためてきたネタなどを。題して、

24時間でステップアップするための

Windows Phone アプリケーション開発における24のパフォーマンスTips

  1. 画像を使うならそのフォーマットを考える
  2. 画像のサイズを考える
  3. メディアファイルを加えるにはコンテンツか、リソースか
  4. 画像を非表示にするもっともよい方法
  5. フレームレートカウンターの見方
  6. タッチ操作はマウスは使わない
  7. ホールドはHoldで
  8. Surface のように画像を操作したい
  9. プログレスバーよりパフォーマンスプログレスバー
  10. プログレスバーよりプログレスインジケーター
  11. 大量データの通信は小さく多く
  12. スプラッシュスクリーンを外してちょっとでも起動を早くする
  13. 動くスプラッシュスクリーンを作りたい、長く表示したい
  14. 別スレッドで処理をする(呼ぶだけ)
  15. 別スレッドで処理をする(読んだ後に処理が必要)
  16. アプリケーションの起動時間を早くする
  17. dll分割で起動アプリケーションのサイズを本気で小さくする
  18. 起動時の重い処理はどこにどうやって?
  19. GPSの更新情報の発生頻度
  20. ApplicationBarIconButton のようなボタンを簡単に使いたい
  21. 沢山のボタン、Click処理だけでもうたくさん
  22. 便利なラムダ式
  23. 正規表現をマスターする
  24. もう開発本はないのか?

では、はじまりはじまり ♪

image 画像を使うならそのフォーマットを考える

Windows Phone ではリッチな表現をするために画像やアニメーションなどを多用します。その時に使えるのは JPEGイメージ、PNGイメージ、そしてXAMLを使ったプリミティブです。ライブラリを使うことでGIFなども使うこともできますが、事実上は難しい。ではどれを使ったらパフォーマンス上よいのか?

  1. 単純な図形を使ったXAMLベースのイメージ
  2. JPEG画像
  3. PNG画像
  4. 複雑なXAMLを使ったイメージ

JPEGとPNGの差は処理の負荷。そのカギは半透明です。これが足を引っ張ることになります。半透明処理のいらないJPGがパフォーマンスで有利となります。

また、拡大縮小しても品質を保つことができるベクトルベースの画像が必要なとき以外はXAMLでの画像よりもJPEG/PNGの画像を使ったほうがよいでしょう。

結論:画像はシンプルなXAMLか可能な限りJPEGで

image 画像のサイズを考える

JPEGがよいからといって油断してはいけません。1300万画素のカメラをもつIS12Tの撮影画像をそのまま使うことはお勧めできません。というのも2048x2048を超えた画像は描画されなくなるため。で、実際には BitmapImage を作成する際に2000ドット未満になるまで1/2縮小を繰り返しているので、BitmapImageを使えばOK。

Uri uri = new Uri("Test3k3kfile.JPG", UriKind.Relative);
BitmapImage bmp = new BitmapImage(uri);
image1.Source = bmp;

この場合、読み込んだファイルの大きさは、3000x3000としても、読み込まれた段階で1500x1500になっている。

結論:画像は自分で小さくしておくか、BitmapImageで小さく

image メディアファイルを加えるにはコンテンツか、リソースか

ファイルサイズがどうしても大きくなるメディアファイルはコンテンツにしましょう。そもそりそーすとコンテンツの違いは

  • リソース:メディアファイルをアプリケーションのDLLに内蔵しされてxapが作られるので
  • コンテンツ:メディアファイルは別ファイルとして扱われxapに内蔵される

で、リソースの場合はこのような処理になる。ファイルサイズの大きいメディアはコピーする時間がネックとなるので、コンテンツが推奨。なぜか?結局実行時ファイルを展開するから。その時に時間がかかってしまう。

  • リソース:アプリケーション起動 → ファイルを展開 → ファイルをコピー → ストリ���ムで読み込み
  • コンテンツ:アプリケーション起動 →  ストリームで読み込み

結論:メディアファイルは展開に時間がかかるのでコンテンツで

image 画像を非表示にするもっともよい方法

オブジェクトを非表示にする場合、Visibillity = Collapsed を使用するが、Opacity=0でもOK。この時に注意は Bitmap Cache の設定だ。簡単に言えば、対象背景を画像として保存して置く設定。Bitmap Cache を作っておけば、

  • 表示非表示の際に切り替わりが速くなる。
  • しかし、対象のオブジェクトが書き換わることがあると、常にキャッシュの書き換えも発生するのでむしろ通常時が遅くなる。

なのでどちらが良いかというのは必ずしも簡単に言えない。

この場合、2つのパターンではなく、3つのパターンに分けられる。Visibillity 、 OpacityでBitmap Cacheの有る無し。

  Visibillity Opacity + BitmapCache ON Opacity + BitmapCache OFF
非表示時のメモリ消費 少ない 多い 少ない
非表示移行への速さ 速い 速い やや速い
表示移行への速さ 遅い 速い 遅い
表示時の負荷 少ない 多い 少ない
おすすめ使用用途 1回だけ消す時
消すものがシンプルなとき
表示非表示をよく切り替える物
対象の書き換えが少ない時
対象が複雑でかつ書き換わることが多い
あまり頻繁に表示非表示は切り換えない

Opacity + BitmapChache ONはパフォーマンスとしてはよいことが多い。しかし、対象物の内容が変わったり、その全面で別のオブジェクトが動くなど、書き換えが多い場合は、通常時のパフォーマンスに影響が出るので注意。

結論:画像の非表示化はケースバイケースで適切な方法を

 

image  フレームレートカウンターの見方

画面右上についているカウンターはフレームレートカウンターは階下の数字が表示されている。

image

Visibillity で Collaplseにすると、本当にGPUに描画処理用に渡されるレートが下がる。表示する必要がないから。ビデオメモリも大幅に下がる。しかし Opacity + Bitmap CacheをONにすると、使用しているビデオメモリは減らない。さらに、画面の更新レートも著しく下がることがわかる。

調整するには以下の値を参考にする。

注意 推奨地 最高値
画面が更新されるレート 30fps以下 45fps 60fps
UIスレッドの実効レート 15fps以下 30fps 60fps
1フレームで描画されるピクセル数 >3.5 <=2.5 3.0

結論:描画がおそい原因を探るにはまずはフレームレートカウンターから

 

image タッチ操作はマウスは使わない

Windows Phone のタッチのイベントはマウスのイベントで取ることができる。

  • MouseLeftButtonDown
  • MouseMove
  • MouseLeftButtonUp

が、同じくSilverlightには、操作用にイベントがある。

  • ManipulationStarted
  • ManipulationDelta
  • ManipulationCompleted

これらのイベントはそれぞれ同じようなタイミングで発生する。ではどちららがいいのか?マウスのイベントは PC用のSIlverlihgtの互換を考えたものであり、パフォーマンスの面からいったらManipulationイベントを使うべきである。大きな差はないかもしれないが、MouseMoveなどは以上に敏感すぎるきらいがある。ホールドしている際にも小さな指の動きでイベントが発生指定しまう。

それから、manipulationを使うと、ピンチを使った拡大縮小の操作も同時に取れる。ManipurationDeltaで取れるのは相対移動距離だが、ManipuationOriginの取得で、Mouseイベントと同じように絶対座標も取得可能だ。

結論:タッチ操作はManipurationイベントで

image  ホールドはHoldで

Windows Phone 7.5ならタップ、ダブルタップ、ホールドがイベントで取れる。

  • Tap:Down → Up → Tap 発生
  • Hold:Down → そのまま維持 → Hold 発生
  • DoubleTap:Down → Up → Tap 発生 → Down → Up → DoubleTap 発生

とくにHoldは便利。MouseやMnipulationを使ってやろうとするとタイマーなどを使わないとできないので。

ただし、Tap と DoubleTap は同時に使う場合、Topが必ず先に発生するので注意したい。

結論:HoldはHoldイベントを使うべし

 

image Surface のように画像を操作したい

拡大縮小、タッチでスライド、そんなあたかも写真を操作するような Microsoft Surface の操作感覚を Windows Phone で実現したい。そんなことを思ったら、MultiTouch Behavior を使ってみよう。

MultiTouch Behavior

image

使い方は、

  1. 解凍したファイルから以下の3つのdllをプロジェクトの参照に追加する
    1. MultiTouch.Behaviors.Silverlight.WP71.dll
    2. System.Windows.Input.Manipulations.dll
    3. System.Windows.Interactivity.dll
  2. Expression Blend でMultiTouhBehavior 画像やプリミティブに貼り付ける。ボタンでも構わない
  3. 必要なプロパティを設定する

結論:MultiTouchBehavior で開発パフォーマンスを上げて最大のユーザビリティを

 

image プログレスバーよりパフォーマンスプログレスバー

時間がかかる処理を行う場合に使うプログレスバーだが、パフォーマンスの低下の原因となる場合がある。ではどうしたらいいか?

ひとまず、Microsoftの担当者が、PerformanceProgressBar を公開している。一応サポート対象外だがパフォーマンスを気にする人は使ってみるといいかもしれない。

結論:プログレスバーにこだわるなら パフォーマンスプログレスバーを試してみよう

 

image プログレスバーよりプログレスインジケーター

ただ、もっと簡単なのがプログレスインジケーター。がめんのシステムトレイの上でプログレスバーが表示されているのを見たことはあるだろう。それを借りること。表示場所など細かい設定はできないが、OSが持っている機能を借りるだけなので簡単だ。

最も簡単に書いた場合はこんな感じになるだろう。もうちょっと落ち着いて書くこともできるが、まぁ簡単にコピペできるように。

public MainPage()
{
    InitializeComponent();

    SystemTray.SetProgressIndicator(this, new ProgressIndicator() { IsIndeterminate = true });
}

private void button1_Click(object sender, RoutedEventArgs e)
{

    SystemTray.GetProgressIndicator(this).IsVisible = true ;
}

結論:プログレスバーにそれほどこだわらないならプログレスインジケーターを使おう

image  大量データの通信は小さく多く

データ通信で大量のデータの取得の際、タイムアウトとなって通信がオフになることがある。バッテリーを考慮しての動きである。もちろん再度要求されて通信がONになるがこのON/OFFの繰り返しのオーバーヘッドは発生してします。

そのため大量のデータを入力する際には、小さくできるものは分けて��れを並列で取得しに行く。こうすることで無線通信のON/OFFによるパフォーマンスの低下を防ぐことができる。

結論:通信でのデータは小さく多く

 

image スプラッシュスクリーンを外してちょっとでも起動を早くする

起動時にはスプラッシュスクリーンが表示される。通信や初期化などで時間がかかる処理に対して、スプラッシュスクリーンが表示されることで待たされている感をなくすことができるという心理的な効果がある。

しかし、もし本当に起動が速いアプリをさらに早くしたい場合はスプラッシュスクリーンを外してしまえばいい。画像とはいえ、読み込み→表示→消去アニメーションとパフォーマンスには影響を与えているから。

スプラッシュスクリーンの設定はどこにもない。起動時に SplashScreenImage.jpg を表示するだけだ。だから、このファイルを消すか名前を変えてやれば読まれなくなる。

結論:自身があるならスプラッシュスクリーンを外してしまえ

 

image  動くスプラッシュスクリーンを作りたい、長く表示したい

例えば、どうしても思い処理があるので、

  • プログレスバーを表示するスプラッシュスクリーンを表示させたいとか
  • アニメーションが動くスプラッシュスクリーンを表示させたいとか、
  • ユーザーに読ませるためにある程度の時間表示したい

ということもあるだろう。しかしそれはできない!。前述のとおりスプラッシュスクリーンの設定などはどこにもなく、ただ起動時に SplashScreenImage.jpg を表示するだけだから。

どうしたらいいか?

スプラッシュスクリーンのような画面を作ってしまえばいい。SplashScreen.xaml のような感じだ。それを起動時に表示させる。そしてそのあとにMainPage.xamlを表示させればいい。ただここでも問題発生だ。SplashScreen.xaml から MainPage.xaml への移動はあからさまにページ遷移に見えてしまう。ではどうしたらいいか?

PopUp である!え?PopUp 知らない?

  • PopUpは UIコンポーネントのひとつである
  • 画面に配置すると最前面に表示される
  • PopUp は Xamlのページを内包できる
  • PopUpは消えるときにはすっと消える

使い方を覚えれば結構便利。表示するものはページとして別管理できるうえにいつでも最前面に表示されるので。

実装例

private Popup popup;

public MainPage()
{
    InitializeComponent();

    this.popup = new Popup();
    this.popup.Child = new SplashScreen();  //SplashScreen.xaml のクラス
    this.popup.IsOpen = true ; //Popupを消すときはこれをFalseに

    //起動時の処理などを記述
}

ポイント

尚、SplashScreenImage.jpg と SplashScreen.xaml の画面をおなじにしておくと、SplashScreenImage.jpg の表示から SplashScreen.xaml への切り替わりがスムースというかほぼわからなくさせることができる。ウマー。

結論:オリジナルのスプラッシュスクリーンはPopUpで作るべし

 

image 別スレッドで処理をする(呼ぶだけ)

さて、オリジナルス スプラッシュスクリーンを表示しているうちに裏で処理をさせたい。そんな時、下手そのまま処理を書いてしまうと画面の表示のパフォーマンスに影響してしまうときがある。これは困る。

どうしたらいい?

Thread である!え?Thread 知らない?

  • 特定の処理を並列処理する
  • なのでユーザーインターフェースの操作を邪魔しない

実装方法

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
   System.Threading.Thread startupThread = new System.Threading.Thread(new System.Threading.ThreadStart(initializePage));
    startupThread.Start();
}

void initializePage()
{
    Thread.Sleep(7000); //重い処理のつもり 
}

これで、並列で重い処理も楽々。

結論:時間のかかる処理は 別スレッドに追い出すべし

 

image  別スレッドで処理をする(読んだ後に処理が必要)

さて、スレッドはいいが、終わった後に戻ってきてほしい。そして、終わった後の処理をしたい。

どうしたらいい?

BackgroundWorkerである!え?BackgroundWorker 知らない?

  • 特定の処理を別スレッドで処理する
  • なのでユーザーインターフェースの操作を邪魔しない
  • 処理が終わったら、イベントが発生して終わった後の処理を進められる

BackgroundWorker の使い方はこんな感じ。

  1. BackgroundWorker のインスタンスを作って
  2. DoWork イベントハンドラで裏で行う処理を実装
  3. RunWorkCompleted イベントハンドラで処理が終了した後の処理を実装
  4. RunWorkAsyncで実行開始!

実装方法

コードは長そうだが、イベントハンドラの実装は、+= のあとに Tab, Tab で自動的にできるので簡単!

private Popup popup;
private BackgroundWorker backroungWorker;

public MainPage()
{
    InitializeComponent();
    backroungWorker = new BackgroundWorker();
    backroungWorker.DoWork += new DoWorkEventHandler(backroungWorker_DoWork);
    backroungWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backroungWorker_RunWorkerCompleted);
    backroungWorker.RunWorkerAsync();
}

// 裏で行う処理
void backroungWorker_DoWork(object sender, DoWorkEventArgs e)
{
    // 処理
}

// 処理が終わった後
void backroungWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    this.Dispatcher.BeginInvoke(() =>
        {
            this.popup.IsOpen = false;
        }
    );
}

PopUp による スプラッシュスクリーンを非表示にしているが、UIとは別のスレッドから UIのスレッドを操作しないといけない。そのために BeginInvoke メソッドを使って処理をしている。

結論:時間のかかる処理は BackgroundWorkerで非同期に処理すべし

 

image アプリケーションの起動時間を早くする

アプリケーションの起動時、思い処理をしていないのに遅い。どうしたら早くなるの?これの多くはアプリケーション自身が重く大きいケースがある。だから重い。

どうしたらいいか?

  • 画像、メディア、外部ファイルは コンテンツにする (メディアの項でやったとおり)
  • 画像のURIを指定するときは 場所がすぐにわかるように 先頭に /を付ける 例:/Image/Cat.jpg

結論:外部ファイルの扱いは外に外に

image dll分割で起動アプリケーションのサイズを本気で小さくする

前述のように小手先の縮小化ではなく本気で起動アプリケーションを小さくする。勘違いしてはいけないのは、アプリケーションは小さくできないから、起動するアプリケーションのアセンブリだけ小さくなるようにするということだけである。

  • PhoneApp1 読み込み(MainPage, page1, page2, page3, page4, page5, page6 ... 読み込み ):遅い
  • PhoneApp1 読み込み(MainPage 読み込み ):早い
      → 処理後 OtherPage.dll 読み込み(, page1, page2, page3, page4, page5, page6 ... 読み込み ):起動時は行わない

分割用クラスライブラリの作成

アセンブリを分けるにはどうしたらいいのか?アセンブリ(dll) ≒プロジェクトである。だから別プロジェクトを作ればいい。クラスライブラリプロジェクトを追加すればいい。

image

追加したら、プロジェクト参照を行う。

image

不要なクラスの削除とページの追加

Class1.cs 入らないから削除して、新しいページを追加する。

image

MainPageから呼び出すには

MainPage.xaml からこれらのページを呼び出すにはこのようなURIとなる。

/PhoneClassLibrary1;component/Page1.xaml

NavgationService を使ってコードで呼び出すならこんな感じ。

NavigationService.Navigate(new Uri("/PhoneClassLibrary1;component/Page2.xaml", UriKind.Relative));

分割の結果

Bin フォルダを見ると2つのアセンブリ(dll)になっていることがわかる。PhoneApp59.dll は PhoneClassLibrary1.dll のおかげで軽量化されたわけだ。

image

結論:起動を早くするならメインのアセンブリは小さく

image  起動時の重い処理はどこにどうやって?

起動時には主に3つ処理が行われる

  1. コンストラクタ(MainPage等)
  2. OnNavigatedTo イベント
  3. Loaded イベント

この3つのイベント、どこで処理を実装しようか悩んだ人は多いはず。実際は コンストラクタや、Loaded は起動時しか呼ばれず、OnNavigatedToは別ページから戻ってきたときも呼ばれるので、その動きの違いだけで決めていることが多いはず。

が、起動時のパフォーマンスの観点から言えば、違う観点で選ぶべきなのである。まずは起動プロセスを見てみよう。

  1. コンストラクタ実行
  2. NavigatedTo 実行
  3. フレームの表示
  4. Loaded実行
  5. 画面の操作可能

このため、起動時の処理で重い処理がある場合はいくつか注意が必要である。

  • コンストラクタ、NavigatedTo が重いと画面表示までが遅くなる (ストレス)
  • Loaded が重いと 画面表示してるのに操作できない時間が長くなる (超ストレス)

なので、とくに Loaded は軽くして、画面は表示しているのに操作できないという状況を作らないようにすべき。で、重い処理は別スレッドで処理させよう。先ほど紹介したThread処理でOK。とにかく早い段階で処理するなら、まぁ、NavigatedToあたりで実行させればよいでしょう。

実装例

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
    System.Threading.Thread startupThread = new System.Threading.Thread(new System.Threading.ThreadStart(initializePage));
    startupThread.Start();
}

void initializePage()
{
     Thread.Sleep(7000); //重い処理のつもり
}

結論:Loadedの肥満に注意

 

image GPSの更新情報の発生頻度

GPSのPositionChangedにはイベント発生のための閾値がある。これが MovementThreshold。単位はメートルで規定値は0になっている。移動距離がこの閾値を超えたときにPositionChanged のイベントが発生する。0の場合はほぼ1秒に1回イベントが起きる。

しかしこんな頻度でイベントが発生したら、バッテリーパフォーマンス上よろしくない。そんなわけで MovementThreshhold を必要最低限の値に変更しよう。

実装例

GeoCoordinateWatcher gps = new GeoCoordinateWatcher();

// コンストラクター
public MainPage()
{
    InitializeComponent();
    gps.MovementThreshold = 20.0;
    gps.PositionChanged += new EventHandler<GeoPositionChangedEventArgs<GeoCoordinate>>(gps_PositionChanged);
    gps.Start();
}

どちらがいいかは、開発者の意図しだい。

結論:GeoCoordinateWatcherPositionChanged イベントはほどほどに

image ApplicationBarIconButton のようなボタンを簡単に使いたい

ApplicationBarIconButton のような丸いボタンを使いたいなら、すぐに画像を探すようではまだまだだ。このくらいなら、なにも用意する必要はないテンプレートを使ってやればパぱっと作ることができる。これこそ開発におけるパフォーマンスの向上だ。

テンプレート実装例

<phone:PhoneApplicationPage.Resources>

    <ControlTemplate x:Key="EllipseButtonTemplate" TargetType="Button">

        <Border x:Name="ButtonBackground"
                BorderBrush="{TemplateBinding BorderBrush}"
                BorderThickness="{TemplateBinding BorderThickness}"
                Background="{TemplateBinding Background}"
                CornerRadius="33"
                Margin="{StaticResource PhoneTouchTargetOverhang}"
                Width="48"
                Height="48">

            <ContentControl
                x:Name="ContentContainer"
                Content="{TemplateBinding Content}"
                RenderTransformOrigin="0.5,0.5">
                <ContentControl.RenderTransform>
                    <ScaleTransform x:Name="buttonScale" />
                </ContentControl.RenderTransform>
            </ContentControl>

        </Border>

    </ControlTemplate>
</phone:PhoneApplicationPage.Resources>

ボタン本体

<Button Content="OK" Template="{StaticResource EllipseButtonTemplate}" />

実行画面

image

結論:テンプレートってすごい

 

image 沢山のボタン、Click処理だけでもうたくさん

同じようなボタンを配置してまとめて処理するなら、すべてイベントハンドラで処理しよう。どこのボタンから呼ばれたかは Sender 変数の中のプロパティで判断すればOK。

<Button x:Name="Button1" Content="Red" Click="Button_Click" />
<Button x:Name="Button2" Content="Blue" Click="Button_Click" />
<Button x:Name="Button3" Content="Yellow" Click="Button_Click" />
<Button x:Name="Button4" Content="Green" Click="Button_Click" />
<Button x:Name="Button5" Content="Black" Click="Button_Click" />
<Button x:Name="Button6" Content="White" Click="Button_Click" />
           :

private void Button_Click(object sender, RoutedEventArgs e)
{
    if ((sender as Button).Content.ToString() == "Yellow")
        MessageBox.Show("正解!");
}

オリジナルのプロパティを使うならユーザーコントロールを作ってしまえ

ただ、ボタンの標準のプロパティではなく、独自のプロパティをつけてボタンごとに設定し、それを使いたい場合はユーザーコントロールを作るのが得策。原稿のボタンから、ユーザーコントロールを作るなら、Expression Blendが簡単。右クリックして、コンテキストメニューから UserControlの作成を選ぶだけ。

image

プロパティを追加

そして、このコードビハインドにプロパティを追加しよう。この時、Visual Studio のプロパティ画面でも設定できるよう、きちんとプロパティとして定義する。

public partial class UserControl1 : UserControl
{
    public Color MyColor { get; set; }
    //public Color MyColor; はNG

    public UserControl1()
    {
        // 変数を初期化するために必要です
        InitializeComponent();
    }
}

イベントも追加

ただ、UserControl には基本的なイベントしかない。なのでClickイベントを作り、ボタンが押されたら、UserControlのClickイベントを発生させる。ここでの引数の型などは基本的にはButtonと同じものを用意している。

public event RoutedEventHandler Click;

private void Button_Click(object sender, RoutedEventArgs e)
{
    if (Click != null)
        Click(this, new RoutedEventArgs());
}

使ってみる

さて、コンパイルしたら、Visual Studio を見る。Visual Studioにはきちんとこのプロパティ MyColor が追加されている。勿論、作成したClickイベントも。

image

image

後は普通にボタンと同じような実装をすればいい。

<UserControl1x:Name="Button1" Content="Red" MyColor=”Red” Click="UserControl1_Click" />
<UserControl1x:Name="Button2" Content="Blue" MyColor=”Blue” Click="UserControl1_Click" />
<UserControl1x:Name="Button3" Content="Yellow" MyColor=”Yellow” Click="UserControl1_Click" />
<UserControl1x:Name="Button4" Content="Green" MyColor=”Green” Click="UserControl1_Click" />
<UserControl1x:Name="Button5" Content="Black" MyColor=”Black” Click="UserControl1_Click" />
<UserControl1x:Name="Button6" Content="White" MyColor=”White” Click="UserControl1_Click" />

private void UserControl1_Click(object sender, RoutedEventArgs e)
{
    ContentPanel.Background = new SolidColorBrush((sender as UserControl1).MyColor);
}

結論:手軽にユーザーコントロールを使ってみよう。

image 便利なラムダ式

効率的な、コーディングのために覚えていて損がないのがラムダ式。例えば、実行時にイベントハンドラを追加するなら、このように書く。+= tabx2 で簡単。

// コンストラクター
public MainPage()
{
    InitializeComponent();

    button1.Click += new RoutedEventHandler(button1_Click);
}

void button1_Click(object sender, RoutedEventArgs e)
{
    MessageBox.Show("Push");
}

しかし、ラムダ式ならもっと簡単に書ける。これなら1行で十分だ。

// コンストラクター
public MainPage()
{
    InitializeComponent();

    button1.Click += (sender, e) => MessageBox.Show("Push");
}

ラムダ式では、まずメソッドの省略(名前なしメソッド)、そしてその定義までまとめて書くことができる。スマートに使いこなせば美しいコーディングが可能。もちろん開発のパフォーマンスを向上させることもできる。

結論:より効率の良い開発のために、ラムダ式も覚えて損はない

 

image 正規表現をマスターする

文章から、特定のパターンの文字列を抽出する正規表現はステップアップにはもってこいの方法。でもそれほど大変ではない。Regex オブジェクトを使って、パターンを定義し、Match関数でパターンに合った文字列を抽出してくれる。

次の例は Webサイトの内容(HTML)から、電話番号を抽出というもの。

WebClient web = new WebClient();
web.DownloadStringCompleted += new DownloadStringCompletedEventHandler(web_DownloadStringCompleted);
web.DownloadStringAsync(new Uri(Url));

void web_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
    String pattern = @"0\d{1,4}[-(]\d{1,4}[-)]\d{4}";
    Regex rgx = new Regex(pattern, RegexOptions.IgnoreCase); 
    MatchCollection matches = rgx.Matches(e.Result);
 
   if (matches.Count > 0)
        for (int i = 0; i < matches.Count; i++)
            if (matches[i].ToString().Length >= 10)
                lstAddress.Items.Add(matches[i].ToString());
}

パターンで使用されている文字例

0:0そのもの
\d:数字
\D:数字以外
\w:英数字とアンダースコア
\W:
{4}:前の文字 4文字 例 9999, 3452, 1234, 9785
{1,4}:前の文字 1~4文字 例 1, 25, 364, 9785
*:直前の文字の0回以上の繰り返し  zo* = z, zo, zoo, zoooo
?:直前の文字の0回か1回  zo? = z, zo
[-)]:- か ) のいずれか

http://msdn.microsoft.com/ja-jp/library/ae5bf541.aspx

Webからの大量の情報から、効率よく特定の内容を撮ってくるのに正規表現は強力な手法です。

結論:Webコンテンツとの相性は抜群

 

image もう開発本はないのか?

現在アプリケーション開発のための本としては、プログラミング Windows Phone が発売されているが、これはどちらかというとリファレンス本。

高橋 忍 は現在、別のタイプの開発本を執筆中らしい。2012年2~3月発売予定だとか。でも本業が忙しくて遅れ気味だとか。

結論:早く書きなさい(このネタもその布石か?)