WPF/日記13
フキダシの表示文字を変更する
フキダシの中のTextBlockは、モデルのマテリアルのブラシのキャンバスの中身という操作しにくい場所にあったため、リソースから呼び出したモデルのオブジェクトに対してどのような操作でTextBlock.Textプロパティを変更してやればいいのか、前回、途方にくれていました。リソースじゃなければ、x:Name属性で名前をつけて、コード上からもその名前を使って操作できたんですけどね。私のとったいくつかのアプローチを以下に示してみます。
スタイルを指定してみよう
スタイルはHTMLのCSSよろしく、複数の要素に対して一括してプロパティを設定してくれる機構です。
<Style TargetType="TextBlock" x:Key="Talk">
<Setter Property="Text" Value="HOGE" />
</Style>
<TextBlock ... Style="{StaticResource Talk}" />
こんな感じでSetterで指定したようにTextBlockのTextプロパティを「HOGE」に変更してくれました。じゃあ、このSetterを操作すればフキダシの文字も変わるんじゃないか?と思ったのですが、Styleの中身は必ずしも実行中に動的に変更できるわけではないようです。IsSealedプロパティがどうのこうのとかいうメッセージが出たので挫折しました。
テンプレートを使ってみよう
スタイルを試す延長で、テンプレートによる操作を試みたりもしました。テンプレートは事前に宣言された形にのっとって、オブジェクトのレイアウトを勝手に設定してくれるものという曖昧な認識であれこれやってみたのですが、ControlTemplateもDataTemplateもどちらも私の問題を解決してくれるような機能ではありませんでした。
前者はButtonのような「コントロール」要素の外観をレイアウトするもので、後者はListBoxのアイテムのレイアウトに関するものでした。
面白そうな仕組みだなあと感心しつつも今回は関係ないので、スルーしました。
データバインディングしてみよう
WPFの醍醐味データバインディングを使えばなんとかなるんじゃないかと思いました。AのプロパティとBのプロパティがあったとして、どっちかが変更された場合、もう一方のプロパティもすかさず変更してくれるなんてことを勝手にやってくれる、何気に縁の下の力持ちなやつです。(必ずしも双方向じゃないんですね。)
<TextBlock ... Text="{Binding ElementName=Input,Path=Text}" />
こんな感じで、メッセージ入力欄のテキストと同期するように指定して、いざ、フキダシを表示させてみました。が・・・データはバインドされず、空欄でした。
もしもこれがリソースの中で定義されたTextBlockではなければ、きっとこれでうまくデータバインディングしてくれたのだと思います。リソースは静的なものなのでリソース内の要素を動的に変更するような仕組みは動かないのではないかというのが、私の現在の推測です。いや、でもバインディングのロジック的にそんなことって・・・リソースを呼び出したときに裏でどんな処理がされているんだろうか。それともどこか構文が間違っているだけの初歩的なミスなんだろうか・・・。
とこんな感じでずっと悶々としていました。
解決策
とりあえず、自分の中で出た答えは初期化イベントでTextBlockを捕捉することです。
<TextBlock ... Initialized="initTalking">
TextBlock currentTalk;
private void initTalking(object sender, EventArgs e)
{
currentTalk = (TextBlock)sender;
}
void viewTalkingBox(string mes)
{
...
talkingbox = (ModelVisual3D)ChatWorld.FindResource("TalkingBox");
currentTalk.Text = mes;
...
}
TextBlockのInitializedイベントで呼び出した関数に呼び出し元のオブジェクトがsenderとして渡されるので、そこでsenderを捕獲しておき、後でsender.Textを新しいメッセージに書き換えるというやり方です。あんまりスマートではない気がしますが、他にもう思いつかなかったので仕方がありません。もっと勉強が進んだら、もっといい方法があるんだろうなと思ってます。
フキダシの操作もできたところで、ひとまず目標は達成しました。これを一般に公開できるように改善していきたいですね。今後はアバタやフキダシのオブジェクト化あたりから手をつけていくつもりですが、この日記もひとまず終了です。またWPFのプロジェクトを思いついたら、日記の続きを書きましょう。