‘WPF’のエントリ

対戦もローカルで動いてきたのでインターネットを介した対戦をしてみた。が,結局対戦はうまくいかず。UXとかバグとかいろいろ課題が分かったので,テスト公開はもう少し修正してから。

課題の一つで,TextBoxの挙動がおかしいというのがあって,以下のようなTextBoxを作ると,IME変換中にIME入力すると,それまでに入力した文字が消えてしまうと言うもの。どうもUpdateSourceTriggerがIME変換時もProperty変更だと思っておかしな動作をするっぽい。


回避策だけど,UpdateSourceTriggerを手動でやればいいかと思って,以下を作ってUpdateSourceTriggerを消してみた。

public class IMETextBox : TextBox
{
    protected override void OnTextChanged(TextChangedEventArgs e)
    {
        GetBindingExpression(TextBox.TextProperty).UpdateSource();
        base.OnTextChanged(e);
    }
}

この後IME変換中だったらUpdateSourceしない処理を付けようとしてたんだけど,何故か上のコードだけでちゃんと動いてしまった。なんか将来動かなくなりそうだけど今は時間がないのでこれで。適当な対策なので,使う場合はWPFのソースを見て原因を調べてから使って下さい。そして原因を教えて下さい。。。

C#のXMLドキュメントコメント。MSが公式に出しているSandcastleを使ってみた。リフレクションをフルに使ってMSDNみたいな形式でドキュメントを出してくれる。標準の型とか親クラスはMSDNへのリンクまで貼ってくれるというやりすぎなツール。

2011092501


GUIのフロントエンドSandcastle Help File Builderってのもあるらしいけど,常に最新版を使うならやっぱCUIよね,ってことで使い方。ちなみにOSはWindows 7 x64,Visual Studioは2010 SP1。SandcastleはJune 2010(Version 2.6.1062.1)。

インストール
  1. Sandcastleの最新版をダウンロード,インストール
  2. 環境変数にDXROOTが登録されるが,間違っているので最後の「」を削除しておく。
ドキュメント生成
  1. Visual Studioのプロジェクトの設定で「XML documentation file」を有効にする。その際ファイル名は「プロジェクト名.xml」じゃなく「comments.xml」にする。
  2. XML Documentation Comments形式で正しくマークアップされたプロジェクトをビルド。
  3. comments.xmlとビルドしたファイルと「C:Program Files (x86)SandcastleExamplesSandcastlebuild_Sandcastle.bat」を同じフォルダにコピーする。
  4. ビルドしたファイルがexeの場合,build_Sandcastle.batを書き換える(※1)。
  5. プライベートメソッド等非公開メンバも出力するには,build_Sandcastle.batを書き換える(※2)。
  6. 上記フォルダで以下を実行。形式は引数によっていろいろ選べる。
    build_Sandcastle.bat
      vs2005 ビルドしたファイル名(拡張子なし) html
※1
修正前:MRefBuilder %2.dll /out:reflection.org
修正後:MRefBuilder %2.exe /out:reflection.org
※2
修正前:MRefBuilder %2.dll /out:reflection.org
修正後:MRefBuilder %2.dll /out:reflection.org /internal+

最近は会社でWPFを使っている。C++の頃と比べるとめちゃくちゃ楽。イメージ的には,WPFではXAML10行くらいですむものをC++でやったら100行かかる,みたいなことを100個作るみたいな。

特に会社でWPFをやって初めて気付いたのがエラー処理の楽さ。C++(Win32 API/MFC)の頃は,UIを駆使するプログラムを書くと何かやる度にエラー処理を何十個も書いていたのだが,WPFだとほとんどバインディングですんでしまってエラー処理がほとんどなくなる。まあ例外に変わっただけと言えないこともないんだけど,それでも入り口にtry-catch書いておけばすむわけで。家プログラミングだとそこまでエラー処理入れないので気付かなかった。


もう一つ。今回は全関数について関数仕様書を書かないといけないかも,みたいな話があって,XML Documentを試してみた。けど結構すごい。関数コメントに書いたものを抽出して勝手にドキュメントができるのは今や当たり前だけど,.NETのはコメントと関数が合ってないとビルド時に警告が出るようになっている。ということは,警告が出なくなるまで修正してやれば,関数コメントは完璧になるわけで。この手のことをやるといつも問題になる,コメントと関数がだんだんかけ離れていくというのがなくなる。Java Docとか最近見てないけどこんな風になってきてるのかなあ。

ただデフォルトでXSLTとスタイルシートがない(と思う)のが残念。Purentroを題材にそれっぽく見えるのを作ってみようかな。

WPFで使っている自作DLLの名称を変更したのだが,どうしてもリソースファイルを旧名称でアクセスしてしまい,Not Foundになる。GrepしてみるとPropertiesResources.Designer.csとSettings.Designer.csの中に旧名称が残っている。この2つはTool Generatedで変更するなと書いてあるのだが,生成元のソースはどこにもない。確かにこのファイルを消してプロジェクトを開き直すと再生成されるのだが・・・。

てことで悩んだ結果,VSSからとってきていることが判明。いつのVisual Studioからか知らないけど,ファイルが足りなかったら勝手にVSSからとってくるようになってたのか。VSSに接続しないようにするとResources.Designer.csもSettings.Designer.csも生成されずにビルドエラーになるので,とりあえず再生成はされないと断定して直接いじることにした。

Visual Studio 2010でWPF(というか.NET)のソースコードレベルデバッグをする方法。MSのブログに載っている2008の方法と同じだが,Tools-OptionsでDebugging-GeneralからEnable source server supportをONにし,Symbolsの一番上に「http://referencesource.microsoft.com/symbols」を追加する。なお,「http://msdl.microsoft.com/download/symbols」とは違うPDBファイルらしいので,既に設定している場合はダウンロード済みのシンボルを一旦削除する必要があるっぽい。

ちなみにWPFのソースコード自体はAvailable Source Code Componentsから落とせる。

楽譜表示のUI部分が完成。だいぶWPFに詳しくなった気がする。あとは楽譜表示に戻って8vaとか未実装な部分を実装すればとりあえずは完成か。


てことでWPF関連。プロジェクトを.NET 3.5ベースにしているとうまくいかないけど.NET 4.0ベースにしたらうまくいったケースがあったのでメモ。.NET 4.0はWindows 7デフォルトで入っていないが,Windows Updateに重要な更新で出てくるし,大丈夫でしょう。


1つ目。CheckBoxにbool型のプロパティをtwoway Bindingしている状況で,ある条件のときはsetterで何もせずに返すようなコードを書いた。チェック操作をしたけどチェックできませんでした,みたいなことをしたいのである。

XAML
<CheckBox IsChecked="{Binding IsDisplay, Mode=twoway}">
C#
 bool IsDisplay
 {
     set
     {
         if(xxx)
         {
             return;
         }
         _isdisplay = value;
         PropertyChanged(this, new PropertyChangedEventArgs("IsDisplay"));
     }
     get
     {
         return _isdisplay;
     }
 }

この状態でチェックボックスをオフからオンに変えようとすると,プロパティはfalseのままなのにUIはtrueになってしまって状態が食い違う感じになってしまう。で結局プロジェクトを.NET 4.0ベースにするとうまくチェックがキャンセルされた。


2つ目。以下のようにListBoxでテキストラベルとそれ以外を配置しているようなケースで,テキストラベルを可変長(Width=”100*”とか)にしている場合,ウィンドウを1度でも広げていれば問題はないのだが,ウィンドウ表示時に画面を狭くしていると,レイアウトが崩れてしまう。

2010082501

2010082502

これも結局プロジェクトを.NET 4.0ベースにするとレイアウトが崩れなくなった。

Expression 4とSilverlight 4 Toolsがリリースされていたので入れてみた。これで.NET 3.5から.NET 4.0に移行できる,んだけどそうするとデフォルトで動かなくなってしまうのだろうか。

WPFのローカリゼーション。どうもMS的にはLocBamlを使う方法を推奨している感じがするが,リソースDLLをビルドしてからバイナリを編集するというのはちょっと気持ち悪い。ということでresxを使うことに。これで合ってるか分からないけどとりあえず最小限のやり方。

  • 最初から入っているResources.resxと同じようにResources.ja-JP.resxを作成し,Propertiesに入れておく。
  • 英語と日本語で同じNameのリソースを作成。
  • .csファイルからはProperties.Resources.XXXで参照する。
  • .xamlファイルからは「xmlns:s="clr-namespace:project.Properties"」のようにネームスペースを参照しておき,{x:Static s:Resources.XXX}として参照する。

なおこれだと言語はOSの表示言語に従うことになる。切り替えたい場合はThread.CurrentThread.CurrentUICultureで切り替えればいいはず。試してないけど。


ここまで作成したものをXPで試してみたが,xmlparseでエラーが発生し,起動できなかった。しばらく調べてみたが原因不明。まあXPは対象外にする予定だからまあいいか。

WPFでボタンをデザイン。C++MFCだとオーナードローでこんなボタンを作ったらそれだけで数日はかかりそうだが,C#+WPF+Expression Blendなら慣れれば1時間くらいでできそう。今までめんどくさくてUIに凝ることもなかったが,これだけの開発環境を用意されるとUI作るのが楽しくなってくる。

2010042001


ちなみに作り方をメモっておく。Expression Blendで普通のボタンを作ってテンプレートの編集。ボタンの中身をごっそり削除して,Ellipseを配置してグラデーションをいい感じに設定。中身にcontaintPresenterをはりつけておく。ここまででデザインは完了。これだとボタンを押しても見た目が変わらないので,トリガータブの「+プロパティ」でIsPressedとかIsMouseOverとか必要なものを追加して,デザインを適当にいじるとイベントが起きたときに差分が適用されるようになる。ここまででスタイル作成完了。Mainのウィンドウに戻って今作ったスタイルをボタンのStyleとして設定。最後にボタンの中身にExpression Designとかで作った絵を貼り付けて完成。

2010042002


ついでにツールチップも付けてみた。色合いを変えて半透明にするためにStyleを変更してみたが,以下のようなコードを書くと,Expression Blendで編集する際に「’ToolTip’は,論理親またはビジュアル親を持つことができません。」というエラーになる。Expression Blendで編集できないだけでVisual Studio 2010ではビルドできて普通に動くのだが,これでいいのだろうか。

2010042003

<ResourceDictionary>
    <Style x:Key="Tip" TargetType="{x:Type ToolTip}">
        <Setter Property="Background" Value="#202020"/>
        <Setter Property="Foreground" Value="White"/>
        <Setter Property="Opacity" Value="0.8"/>
    </Style>
</ResourceDictionary>
----
<Window>
    <Button Style="{DynamicResource PanelButton}">
        <Button.ToolTip><ToolTip Style="{DynamicResource Tip}">次のページ</ToolTip></Button.ToolTip>
            <Canvas Width="16" Height="16" Background="{DynamicResource NextButton}"/"
    </Button>
</Window>
		

休み中ずっとWPFをいじっていた。C#のインテリセンス具合とかベクタグラフィックを直接扱えるのとかいい感じ。