ぺぷしのーげん

アプリケーションエンジニアによる雑記ブログ

Viewで触れるとWPFのバインディングが解除されてしまう

f:id:hazakurakeita:20160610003447j:plain

WPFのバインディングが途中で動作しなくなる事案が発生しました。最初は動作していたのに、特定のタイミングだけ動作しないのです。まさかと思って調べて試してみたら動作しました。そうです、バインディングはとある動作で解除されてしまうのです。。。

 

作成したコントロールの概要

f:id:hazakurakeita:20160624004346p:plain

始まりはVisibilityの変更でした。テキストボックスとテンキーを持つユーザーコントロールを作成し、テキストボックスにフォーカスが移るとテンキーを表示するというものです。GetFocusイベントでテンキーを表示し、LostFocusでテンキーを非表示にしていました。そして、テンキーのクリックはCommandを使ってテキストボックスに値を入力させていました。

 

Visibilityが効かない

private void GetFocus(object sender, EventArgs e)
{

  Keypad.Visibility = Visibility.Visible.

}

private void LostFocus(object sender, EventArgs e)
{

  Keypad.Visibility = Visibility.Collapsed

}

すると問題が発生します。テンキーをクリックした瞬間にテンキーが消えます笑。そうです。テンキー触った瞬間にLostFocusが走るというケアレスミス。しょうがないので、とりあえずテンキーにあるEnterキーでテンキーを非表示にすることにしました。しかしこれが動かない。数字入力は動くので、バインディングできているハズなのですが、Enterキーを押してもテンキーが消えません。

 

Viewでバインディングプロパティに触れてはダメ

private void LostFocus(object sender, EventArgs e)
{

  // Viewで触った瞬間にViewModelとのバインディングが解除
  Keypad.Visibility = Visibility.Collapsed

}

原因は原因はViewのGetFocusイベントにありました。イベント内でテンキーのVisibilityを非表示にしていますが、このときにVisibilityのViewModelとのバインディングが解除されていたのです。以降、ViewModelからテンキーのVisibilityは変更できなくなります。つまりは、バインディングしているプロパティに対して外部から変更が加わると、そのバインディングは解除されるというわけですね。まあ、冷静に考えてみたらそれもそうかという感じですが、焦っていると気付くまでツボにハマってしまいそうですねー。

 

解決策

private void LostFocus(object sender, EventArgs e)
{

  viewModel.CloseKeypad();

}

ViewModelに変更させるようにしましょう。どうしてもイベントで変更したい場合は、イベントメソッドからViewModelのメソッドを呼びましょう。MVVMパターンとしては気持ち悪いですけどね。そもそもWPFでイベントを使うなって話なので、しょうがないのです。そもそもLostFocusイベントだとテンキーに触れただけでコールされてしまうので、結局上のようなコードも使いませんでしたが。

 

おしまい。