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

単一行選択のDataGridについて

環境/言語:[WinXP Pro、.NET 1.1、WinForms]
分類:[.NET]

お世話になります。

仕事では未だに .NET 1.1 の DataGrid を使っております。
前任者から引きついだ既存のコードの中に、こちらで公開されている単一行選択DataGridそのまんまのコードがありました。

ところで、掲載されているコードですと、Shift + PageUp | PageDown での複数行選択ができてしまいます。
お時間のある時に改修をお願いできますでしょうか。

また、Shift + ↑ | ↓ を押した際、ProcessCmdKey で return true; としてしまっているため、何も動きがありません。
これを、Shift なしでキーを押したときと同様の挙動にしたく、return true; を
return base.ProcessCmdKey( ref msg, keyData ^ Keys.Shift );
に書き換えたところ、↑↓キーは期待通りの動きになったのですが、PageDown と PageUp ではやはり複数選択されてしまいました。
Shift なしの PageUp | PageDown 動作にする方法はありますでしょうか?
■No19068に返信(シャノンさんの記事)
> ところで、掲載されているコードですと、Shift + PageUp | PageDown での複数行選択ができてしまいます。
> お時間のある時に改修をお願いできますでしょうか。

ご指摘、ありがとうございました。ProcessCmdKeyに次のようなコードを追加するというので大丈夫でしょうか?

if ((keyData & Keys.Shift) == Keys.Shift &&
(keyCode == Keys.PageUp || keyCode == Keys.PageDown))
return true;

> Shift なしの PageUp | PageDown 動作にする方法はありますでしょうか?

シャノンさんのお書きになっているShift+上下キーと同じ方法ではできないでしょうか?
■No19083に返信(管理人さんの記事)
> ご指摘、ありがとうございました。ProcessCmdKeyに次のようなコードを追加するというので大丈夫でしょうか?
>
> if ((keyData & Keys.Shift) == Keys.Shift &&
> (keyCode == Keys.PageUp || keyCode == Keys.PageDown))
> return true;

はい。
↑↓キーと同じ if 文で判定しても構いませんが、この方法でも構いません。

>>Shift なしの PageUp | PageDown 動作にする方法はありますでしょうか?
>
> シャノンさんのお書きになっているShift+上下キーと同じ方法ではできないでしょうか?

できませんでした。

if ((keyData & Keys.Shift) == Keys.Shift &&
(keyCode == Keys.PageUp || keyCode == Keys.PageDown))
return base.ProcessCmdKey( ref msg, keyData ^ Keys.Shift );

としても、複数選択されてしまいました。
> if ((keyData & Keys.Shift) == Keys.Shift &&
> (keyCode == Keys.PageUp || keyCode == Keys.PageDown))
> return base.ProcessCmdKey( ref msg, keyData ^ Keys.Shift );
>
> としても、複数選択されてしまいました。

原因が分かればもっと良い方法がありそうですが、とりあえずはShift+PageUp、PageDownが押されたときにGridVScrolledメソッドで表示位置を先頭か末尾にするという方法が使えるのではないでしょうか。
■No19096に返信(管理人さんの記事)
>>if ((keyData & Keys.Shift) == Keys.Shift &&
>> (keyCode == Keys.PageUp || keyCode == Keys.PageDown))
>> return base.ProcessCmdKey( ref msg, keyData ^ Keys.Shift );
>>
>>としても、複数選択されてしまいました。
>
> 原因が分かればもっと良い方法がありそうですが、とりあえずはShift+PageUp、PageDownが押されたときにGridVScrolledメソッドで表示位置を先頭か末尾にするという方法が使えるのではないでしょうか。

原因がわかりました(Reflectorで逆アセンブルしました)。
DataGridはProcessCmdKeyをオーバーライドしておらず、実際のキー処理は、OnKeyDownから呼ばれるProcessGridKeyで行っています(このメソッドはオーバーライドできません)。
さらにさかのぼると、Control.OnKeyDownはControl.ProcessKeyEventArgsから呼ばれますが、ProcessKeyEventArgsがOnKeyDownに渡すKeyEventArgsを作る時に、ProcessCmdKeyに渡した、ShiftをクリアしたkeyDataを使っていない模様です。
このため、DataGridに固有の問題ではなく、Controlに起因する問題だと思われます。

ProcessCmdKey では true を返すのみとし、行選択処理は自分で行うのが正解のようです。
GridVScrolled では、スクロールバーが無い場合にうまくいかないようですので、別の方法を探ってみたいと思います。
2007/02/16(Fri) 10:34:16 編集(投稿者)

■No19099に返信(シャノンさんの記事)
> ProcessCmdKey では true を返すのみとし、行選択処理は
> 自分で行うのが正解のようです。
> GridVScrolled では、スクロールバーが無い場合に
> うまくいかないようですので、別の方法を探ってみたいと思います。

このようにしました。
なお、以下で使っているCountプロパティは、
http://dobon.net/vb/dotnet/datagrid/rowscount.html
を利用して実装したものです。

if((keyData & Keys.Shift)==Keys.Shift)
{
    switch(keyCode)
    {
        case Keys.Up:
            this.CurrentRowIndex = Math.Max( 0, this.CurrentRowIndex - 1 );
            break;

        case Keys.Down:
            this.CurrentRowIndex = Math.Min( this.Count - 1, this.CurrentRowIndex + 1 );
            break;

        case Keys.PageUp:
            this.CurrentRowIndex = Math.Max( 0, this.CurrentRowIndex - this.VisibleRowCount );
            break;

        case Keys.PageDown:
            this.CurrentRowIndex = Math.Min( this.Count - 1, this.CurrentRowIndex + this.VisibleRowCount );
            break;

        default:
            return base.ProcessCmdKey(ref msg, keyData);
    }

    return true;
}
解決済み!
コードが引用色になっちゃって見にくいですが、直す方法が分からないので勘弁してください。
解決済み!
2007/02/17(Sat) 04:13:07 編集(投稿者)

> ProcessCmdKey では true を返すのみとし、行選択処理は自分で行うのが正解のようです。

WndProcでなんとかする方法もあるかもしれませんが、きっとシャノンさんのおっしゃる方法が正解ですね。

> GridVScrolled では、スクロールバーが無い場合にうまくいかないようですので、別の方法を探ってみたいと思います。

PageUp,PageDownの動作を勘違いしていました。失礼しました。
解決済み!

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