主にプログラミングに関して。Python, .NET Framework(C#), JavaScript, その他いくらか。
記事にあるサンプルやコードは要検証。使用に際しては責任を負いかねます

スポンサーサイト

                
tags:
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

C#, WPF: デスクトップアプリを作るときのTips

                
 昔はオーディオマニアへの道に片足をつっこんでアンプやスピーカーをそろえていたが、利便性に魅力を感じてすっかりPCで楽曲を聴くようになった。そんなもんでWindowsMediaPlayerやVLCなどを使って聴いていた。それらは豊富な機能を有していたが、ただ聴きたいだけなのに機能が豊富すぎてなんかめんどかった。なのでデスクトップアプリとしてオーディオプレーヤーを自分で作って使ってきた。
 最初のプロトタイプができてから必要最低限の機能追加を行って自分にはだいぶ使いやすいものになってきた。その過程でデスクトップアプリ作成に役立つかもしれないコツがいくつかあったのでまとめておく。
1412111551445.jpg


・.NET Framework環境での言語
 .NET Frameworkで使える言語はC#、VB.NETをはじめとしてPythonの一種で.NETのクラスやPythonの標準モジュールも使えるIronPython、ゲーム開発環境Unityで開発されたPythonのように書けるC#モドキなBoo、さらにはもっとマニアックな言語などさまざまな選択肢がある。ここは自分の手慣れた言語を選んで作ることができる。ぼくは実際このオーディオライブラリにあるファイルを再生するデスクトップアプリをWPFでIronPythonを使って作り始めて、興味からBooに移植して最終的にC#でも書いた。.NET Frameworkの標準であるC#が一番手間なく作成でき、IronPythonやBooでやるのは少しだけ手間があった。
C#のコーディング規則: http://msdn.microsoft.com/ja-jp/library/ff926074.aspx


・WPFの要素にイベントを付加する
 デスクトップアプリ作成ではボタンなどの要素にクリックイベントやマウスオーバーイベントをつけていく。UIは通常XAMLというXML互換のあるマークアップで書くが、HTMLと同じようにXAML側でイベントをつける書き方ができる。
<Button Click="Clicked">Push</Button>
ただし上記より下記のほうがUIとロジックの分離ができているということでいい。
XAML side: <Button Name="pushButton">Push</Button>
code side: pushButton.Click += Clicked;


・イベント付加の書き方
 UI要素へのイベント付加には上に書いたような、定義済みメソッドを登録するやり方と、ラムダ式を使ったやり方がある。
pushuButton.Click += (target, e) => {Console.WriteLine("Pushed");};
 どちらもパフォーマンスに差は与えないものらしい。違いとしてはラムダ式を使うと登録解除ができないということ。
可: pushButton.Click -= Clicked;
不可: pushuButton.Click -= (target, e) => {Console.WriteLine("Pushed");};
あとラムダ式ならばそれが定義されているメソッドにもスコープが及ぶので、クロージャとして使うこともできる。
参考: http://ufcpp.net/study/csharp/sp3_lambda.html


・マルチスレッドでUI要素の変更
 オーディオファイルのメタ情報を読んでアルバムごとに曲をわけてサムネイル画像を抽出して・・・・・・とライブラリの全ファイルにやっていると時間がかかる。膨大なファイルがローカルでなくサーバにあればなおさら。ライブラリ全ファイルを読み込んでから表示とやっていると場合によっては、起動から何分経過したら使えるようになるんだということになる。なのでGUIスレッドとは別のスレッドを用意して、そちらに準備ができたアルバムをUI要素として追加してもらう。
 別スレッドは下記のように立てる。
var thread = new Thread(new ThreadStart(SomeMethod));
thread.SetApartmentState(ApartmentState.STA);
thread.IsBackground = true; //set True: Stop thread when Window1 closes
thread.Start();

 別スレッドで呼ばれたメソッドから既に存在しているUI要素をいじるのは以下のように。
private void SomeMethod()
{
stackPanel.Dispatcher.Invoke(AddChildren);
}

private void AddChildren()
{
var textBlock = new TextBlock();
stackPanel.Children.Add(textBlock);
}

参考:http://msdn.microsoft.com/ja-jp/magazine/cc163328.aspx


・ループ毎に時間がかかりそうな処理はイテレータを使う
var albums = GetAlbums();
foreach (var album in albums)
{
var button = MakeButton(album);
stackPanel.Children.Add(button);
}

 音楽ファイルのメタ情報を読んでアルバムごとにわける。これをすべてのファイルのメタ情報解析が終わるまで待っているのは耐えられない。アルバムとして曲がそろったものから順次UI要素として追加していきたい。
private IEnumerable<Album> IterateAlbum()
{
for (var..........)
{
var album = new Album(info);
yield return album;
}
}

private void AddButtons()
{
foreach (var album in IterateAlbum())
{
var button = MakeButton(album);
stackPanel.Children.Add(button);
}
}

参考:http://ufcpp.net/study/csharp/sp2_iterator.html


・オブジェクトを保存する(シリアライズ、デシリアライズ)
 少し集めるのに時間がかかったデータがディクショナリなどのようなオブジェクトに入っているとする。これをファイルにそのまま保存して、そのファイルを読み込んでオブジェクトを再現できればデータ集めの時間を省略できる。
 別の言語で書いたアプリケーションなどでオブジェクトのデータを使いたければXML、YAML、JSONなどのドキュメントにシリアライズする手がある。そうでもなくそのアプリケーションでしかデータを使わないならばBinaryFormatterを使えばいい。
using (var stream = new System.IO.FileStream(@"data.dat", FileMode.Create, FileAccess.Write))
{
var formatter = new BinaryFormatter();
formatter.Serialize(stream, dataObj);
}

 自作クラスのインスタンスをこれを使ってシリアライズ可能にしたければ定義時に下記のように。
[Serializable()]
public class MyClass
{

デシリアライズ(オブジェクト復元)
using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
{
var formatter = new BinaryFormatter();
myObj = (MyClass)formatter.Deserialize(stream);
}

参考: http://msdn.microsoft.com/ja-jp/library/et91as27.aspx
            

コメントの投稿

非公開コメント

プロフィール

hMatoba

Author:hMatoba
Github

最新記事
リンク
作ったものなど
月別アーカイブ
カテゴリ
タグリスト

検索フォーム
Amazon
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。