ListBox
文字列をリストして選択するなら特に変わったことはないのですが、プログラムから制御しようとして気が付いた点です。インテリセンスのようにキー入力のたびに選択を変えていくようなもの作りました。
1.ListBoxの構造
常にそうかどうかはわかりませんが以下の構造でした。
| ListBox |
Border |
Grid |
ScrollViewer |
| |
|
|
ScrollContentPresenter |
| |
|
|
ScrollBar |
| |
|
|
ScrollBar |
2.行選択とスクロール
ここで使う行選択はシングルです。
IsTextSearchEnabledがあり、ListBox自体でキー入力に応じて適切に表示できますが、今回は検索対象はRichTextBoxの表示文字列なのでプログラムで記述して検索表示します。
- 行を選択してもスクロールは起きない。(ListBoxの表示は変わらない。)
- ScrollIntoView()で、選択行を表示領域内へスクロールする。
- 概ね、表示領域の最下行に表示される。
文字を先頭から入力していくわけなので、用があるのは通常、選択されている行の下方です。どうも、最下行は許容できません。
結局、座標を計算して、中央付近までスクロールを調整しました。
- ScrollIntoView()を行って、選択行を表示領域へ
- UpdateLayout()で、配置情報を確定。
- 表示領域の中心と行の位置の差を行の高さで割って移動行数を計算。(行は同じ高さの前提)
- ScrollViewerのLineUp(),LineDown()を使って調整。
※ScrollIntoView()で指定する項目を変える手もあるが、ScrollIntoView()で最下行になると言う保証がない。
3.前の選択項目
インテリセンスでは、入力間違い(文字を入力していて該当するメンバがない)状態になると、選択が解除される。このとき選択されていた行が水平線に挟まれて表示されている。これを間違いの理由を知る参考にしている。
SelectionChangedイベントで、AddItemsがゼロ件なら、RemovedItemsをペンディング項目として記憶して置く。表示は背景をグレーにした。
AddItemsが指定されたときに、ペンディングがあれば解除する。背景はnullにする。
4.ListBoxItem の実行時エラー
以下のように、すると、
- private void grid1_Loaded(object sender, RoutedEventArgs e)
- {
- ListBoxItem lbi = new ListBoxItem();
- lbi.Content = "123";
- }
実行時に、以下のエラーがでる。これは、デバッグ出力で、動作は継続する。実害はない。
- System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.ItemsControl', AncestorLevel='1''. BindingExpression:Path=HorizontalContentAlignment; DataItem=null; target element is 'ListBoxItem' (Name=''); target property is 'HorizontalContentAlignment' (type 'HorizontalAlignment')
- System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.ItemsControl', AncestorLevel='1''. BindingExpression:Path=VerticalContentAlignment; DataItem=null; target element is 'ListBoxItem' (Name=''); target property is 'VerticalContentAlignment' (type 'VerticalAlignment')
- Content を 設定しない場合は発生しない。
- インスタンスして放置することに問題があるらしい。
ListBoxに繋いで、表示している場合はエラーは表示されない。
- インテリセンスのようなものを作ろうとして、Popup に ListBox を置いた。必要になるまで、表示しないが、このエラーが発生する。
表示しないとListBoxに繋いであっても発生するようだ。
- ListBoxItem を継承していたのを TextBlock にした。
5.行選択と UP、DOWN キー
ListBoxで、プログラムから行を選んで、ListBoxにフォーカスを設定する。
DOWN キーを押す。
すると、選択行が下に移動するわけではなく、先頭の行が選択される。
これは、選択とは別に、UP、DOWNで移動する「何か」あるのかと思って探したが見つからない。UP、DOWNで選択も移動することから、最初のキーで単に初期化されているだけなのかもしれない。
PreviewKeyDownイベントで、UP,DOWNキーを取り上げる以外は上手くいかなかった。(KeyDownは、発生しない。)
- public class LBI : ListBoxItem
- {
- }
- List<LBI> list = new List<LBI>();
- private void grid1_Loaded(object sender, RoutedEventArgs e)
- {
- for (int i = 0; i < 10; i++)
- {
- LBI lbi = new LBI();
- lbi.Content = i.ToString();
- list.Add(lbi);
- }
- ListBox lb = new ListBox();
- lb.PreviewKeyDown += new KeyEventHandler(lb_PreviewKeyDown);
- lb.ItemsSource = list;
- grid1.Children.Add(lb);
- lb.SelectedIndex = 5;
- lb.Focus();
- }
- void lb_PreviewKeyDown(object sender, KeyEventArgs e)
- {
- ListBox lb = sender as ListBox;
- if (lb.SelectedIndex >= 0)
- {
- if (e.Key == Key.Up)
- {
- if (lb.SelectedIndex > 0)
- lb.SelectedIndex--;
- e.Handled = true;
- }
- else if (e.Key == Key.Down)
- {
- if (lb.SelectedIndex < (lb.Items.Count - 1))
- lb.SelectedIndex++;
- e.Handled = true;
- }
- }
- }
一覧
| |
|
|
|
| メソッド |
|
|
|
| |
|
|
|
| ScrollIntoView |
指定した項目を表示範囲へスクロールする。 |
|
|
| |
|
|
|
| |
|
|
|
| |
|
|
|
| プロパティ |
|
|
|
| IsTextSearchEnabled |
項目選択を自動で行い表示を更新 |
|
|
| SelectionMode |
SelectionMode.Single
SelectionMode.Multiple
SelectionMode.Extended |
Extendedは、へんかんきーで、Single/Multipleが切りけられることらしい |
|
| |
|
|
| |