2010年3月2日火曜日

英単語勉強用アプリ作成シリーズ ~ ListBoxでの思わぬ落とし穴

基本機能はほぼ網羅し、着々とアプリのほうは仕上がりつつあるのだが、こまごまとしたところで問題があるので暇を見つけてはプチプチとつぶしている日々の中で思わぬ落とし穴に数日間はまったのでそれの解説をしようと思う。


上記の画像にあるように、英単語勉強用アプリ(を改めてMr. Gengo)は辞書データを自分の好みの形へ改修できるようにしてある。それが上記のJMDictModifierなのだが、かなり困った問題があった。それは「Add Entry」「Add POS」でそれぞれのListBoxへアイテムを追加すると、追加されたアイテムがそれぞれのListBox内でまとめて選択されてしまうという現象だった。その現象は下記の画像の通り。


Ohとうならざるを得ない現象なのだが、複数行を同時に選択してしまうのはひとまず良しとして(SelectionMode=Singleにしているのでアプリ的にはまったくよくないのだが)、もっと深刻な問題はDeselectできないこと。選べるのに一度選ぶとはずせない。アイテムの追加はXAML上ではなくプログラム上で行っているのでその追加のコードが悪いのかと色々と試してみたけれど効果がない。まぁ悪いも何もObservableCollectionに対してアイテムを追加しているだけのプログラムなので試す方法も限られている。仕方がないのでGoogle先生に尋ねてみたら同じような現象で悩んでいる人が居た。

WPF ListBox Selection Problem when changing an item - Stackoverflow

実装している動作は違うようだが、発生している現象は同じようだ。それなので回答に寄せられている方法を色々ためしてみた。しかしどれも効果がない。それはそのはずで、そもそもIsSynchronizedWithCurrentItem=Trueってのは言われなくともやっているし、CollectionViewSourceを作れ!というのも元になるListをObservableCollectionでラップしてからBindしているのでやろうとしていることは同じだ。

万策尽き果てて困りつつも、ポチポチと動かないときの動作確認をしていたら、あるときは動作することを見つけた。それは、アイテムに表示されている内容がすべて異なる場合に正常動作していた。The fuck?と思いつつもどうやらListBox内でアイテムを一意に特定することができずに、同一データ内容のアイテムがまとめて選択されているようだった。「えー?!ListBox内のアイテム比較をデータ内容でやってるのー?まじー?ありえなーい」と驚愕していたら自分の過ちに思い至った。過ちは以下のコード。EntryクラスはListBoxのItemsSourceにBindされているObservableCollectionのアイテムクラスだ。

public class Entry {
// ---省略---
        public override bool Equals(object obj)
        {
            if (obj is Entry)
                return (obj as Entry).Kanji == this.Kanji;
            return false;
        }
// ---省略---
}

ひゃーーー!!!!!恥ずかしいっ!!!アイテムの比較をデータ内容でやっているのは私でしたっ!!

他の箇所でEntryクラスのデータ内容で比較するプログラムがあったので格好つけて「Equalsクラスを上書きしてスマートに比較するかな!キリッ」とかやったらご覧の有様でした。こんなくだらんことで四日間ほども悩んでいたのがアホらしすぎて泣けてくる。

0 件のコメント:

コメントを投稿