DOBON.NET DOBON.NETプログラミング掲示板過去ログ

ComboBoxのリスト表示されている状態で強調色にある行を削除させたい

環境/言語:[Win7 32bit C# .Net Framework4.0 VisualStudio2010]
分類:[.NET]

お世話になります。
自分での考えおよび調査において行き詰ったため質問させていただきます。

【開発環境】
Win7 32bit
C#
.Net Framework4.0
VisualStudio2010


【目的の処理の流れ】
・ComboBoxの「▼」ボタン押下でリスト一覧表示
・リスト内の特定の行にOnMouseで特定の行が強調色に変更(Clickはしない)
・強調色の行を「Delete」キー押下でリストから削除

以上の流れです。
現在下記のコードで試してみたのですが、ComboBoxのSelectedIndexが-1を取得することがあり、思い通りの処理になってくれません。
コードの修正もしくは上記処理の解決策等を御教授いただけると幸いです。

【上手くいかないコード】
________private void ComboBox1_KeyDown(object sender, KeyEventArgs e)
________{
____________//コンボボックスが選択状態にあるとき
____________if (ComboBox1.Focused)
____________{
________________//オブジェクトをComboBoxへキャスト
________________ComboBox combobox = (ComboBox)sender;
________________//Deleteキーが押下
________________if (e.KeyCode == Keys.Delete)
________________{
____________________//ComboBoxのリスト内で強調色にあたる行を削除
____________________ComboBox1.Items.RemoveAt(combobox .SelectedIndex);
________________}
____________}
________}

どうぞよろしくお願いします。
■No32577に返信(れあさんの記事)
> ・強調色の行を「Delete」キー押下でリストから削除

現在のコードだと、ComboBoxStyle.DropDown モードの場合に、
テキスト部に対する Delete なのか
アイテムに対する Delete なのかが判断できないですね。

「ドロップダウン中かどうか」も判定条件に入れたほうが良いかも。



> ComboBoxのSelectedIndexが-1を取得することがあり、思い通りの処理になってくれません。

ドロップダウンしている最中に、項目数が 0 にされると、
内部エラーを起こすみたいですね。

とりあえず、これでどうでしょうか?



private void comboBox1_KeyDown(object sender, KeyEventArgs e)
{
    ComboBox combo = (ComboBox)sender;
    if (combo.Focused && combo.DroppedDown && e.KeyCode == Keys.Delete)
    {
        int index = combo.SelectedIndex;
        if (index != -1 && combo.SelectionLength == combo.Text.Length)
        {
            combo.Items.RemoveAt(index);
        }
    }
}

private void comboBox1_DropDownClosed(object sender, EventArgs e)
{
    var items = ((ComboBox)sender).Items;
    if (items.Count == 0)
    {
        items.RemoveAt(items.Add(new object()));
    }
}
■No32578に返信(魔界の仮面弁士さんの記事)

魔界の仮面弁士様

詳しい説明及びコードの提供ありがとうございます。


> ComboBoxStyle.DropDown モードの場合に、
> テキスト部に対する Delete なのか
> アイテムに対する Delete なのかが判断できない

そもそもComboBoxの動きを理解しておらずお恥ずかしい限りです、、、
DropDownのOpen、Closeに関わらず[ComboBox.Items.Remove()]でItemの削除になるものと考えておりました、、、


> 「ドロップダウン中かどうか」も判定条件に入れたほうが良いかも。

上記のご指摘から判定条件に加えさせていただきたいと思います。



> ドロップダウンしている最中に、項目数が 0 にされると、
> 内部エラーを起こすみたいですね。

「DropDown中に項目数が0になる」挙動は通常の操作では起こりえない動きのためなのでしょうか・・・?
提供していただいたコードにあるように項目数に対する条件判定を独自に入れる必要があるのですね。


提供していただいたコードを元にサンプルを作成したところ、思い通りの削除が行えました。
しかし、リストを開いた状態のままだと削除された空白が増えるのが気になるため、
[comboBox1.DroppedDown = false;]で毎回DropDownを閉じることで回避策としようと思います。

また今回のComboBoxのStyleにDropDownListを用いる予定なのですが、
DropDownListだと[combo.SelectedText]に値が格納されないようですので、条件式を改良することで目的の動作を遂げることができました。



Controlの仕様がわかっていないという初歩的なお恥ずかしい質問内容にも関わらず、わかりやすいご回答を下さった魔界の仮面弁士様本当にありがとうございました。
解決済み!
2014/09/02(Tue) 13:48:59 編集(投稿者)

■No32579に返信(れあさんの記事)
>> テキスト部に対する Delete なのか
>> アイテムに対する Delete なのかが判断できない
> DropDownのOpen、Closeに関わらず[ComboBox.Items.Remove()]でItemの削除になるものと考えておりました、、、

その認識で正しいですよ。

ただ、DropDownList のスタイルとは異なり、
Simple スタイルや DropDown スタイルの場合には
TextBox 部が付与していますので、『Delete キー操作』を
テキスト部の修正の目的に使おうとした場合に都合が悪いかな、と
思った次第です。

ListBox の IndexFromPoint のように、マウス座標からの
ヒットテストの機能があれば良いのですけれどね…。


> 「DropDown中に項目数が0になる」挙動は通常の操作では起こりえない動きのためなのでしょうか・・・?

サポートに問い合わせてみないと分かりませんが、恐らくは
想定していない処理であったのかもしれませんね。

ドロップダウン中に 0 件にすると、ドロップダウンが閉じた時
(void WmReflectCommand メソッド内の CBN_CLOSEUP 時)に
例外が発生しています。

http://referencesource.microsoft.com/#System.Windows.Forms/ndp/fx/src/winforms/Managed/System/WinForms/ComboBox.cs

どうやら .Items.Count が 0 になったにも関わらず、そのタイミングでは
SelectedIndex(というよりは、CB_GETCURSEL メッセージ?)が -1 ではなく
0 を返してしまっているようで、それが GetItemText(Items[0]) 相当の
処理に繋がってしまい、内部で例外を発してしまう模様…。


> 提供していただいたコードにあるように項目数に対する条件判定を独自に入れる必要があるのですね。
肝となるのは、DropDownClosed イベントで Items を編集している点です。
追加と削除を行うことで、上記 SelectedIndex の不一致動作が
回避されるようです。


> [comboBox1.DroppedDown = false;]で毎回DropDownを閉じることで回避策としようと思います。
項目数が少ない時には、リストを開いたまま高さが縮んで欲しかったのですが、
ドロップダウンを MoveWindow API で縮めるなどの力技しか思い当たらず…。
解決済み!
> TextBox 部が付与
なるほど。Delキーの操作がリスト部かDropDownList以外に用意されるTextBoxのText部なのかということでしたか!


> ListBox の IndexFromPoint のように、マウス座標からの
> ヒットテストの機能
場合によってはListBoxを利用する方が今回のような処理には向いてそうですね。


> 追加と削除を行うことで、上記 SelectedIndex の不一致動作が
> 回避される
この点にもとても悩まされました。
削除を行うことでIndexの値がずれてしまい「Indexの値が無効です」の言葉と何度対面したことか。。。


>MoveWindow API で縮める
力技と仰いましたがやり方がないわけではないのですね!
今回は前述のように無理矢理リストを閉じることで対応しましたが、そういった手法も勉強しておけば様々な対処ができそうですね!


魔界の仮面弁士様
詳しい補足説明心より感謝申し上げます。
また本掲示板でお世話になると思いますが、どうぞよろしくお願いします。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板