none
DataGridViewのCellBeginEditの2重発生の抑制 RRS feed

  • 質問

  • いつもお世話になっております。

    DataGridViewのCellBeginEditについて、状況によって2回発生してしまうことがあるようで、
    その対処方法について相談させていただきたいです。

    パラメーターを編集する機能として、
    No列、名称列、設定値列の3列×データ数行のグリッドがあり、
    起動時に対象の持っている現在データを表示し、
    ユーザーが設定値部分を編集して終了時に保存するという機能があります。
    設定値は基本的には単なる数値で、グリッドのデフォルトの挙動で対応しています。
    ただし、中には特殊なフォーマットのデータがあり、セルへの直接入力ではやりにくいため、
    それらについてはCellBeginEditにて編集モード移行をキャンセルし、
    別途入力用のダイアログを表示して設定させるという方法をとっていました。
    しかし、表題のようにイベントが2回発生してしまう場合があり、
    ダイアログで設定して終了した後にもう一度ダイアログが表示されてしまうという現象が発生します。

    どうもセルに対して0キーを入力して編集モードに移行しようとした際に、
    CellBeginEdit内で編集モードへの移行をキャンセルすると、
    もう一度CellBeginEditが呼び出されてしまうようです。
    (追記:無駄なコードを省くため、新規のプロジェクトで確認を行いましたので、
        ハンドラーの多重設定や別途イベントを発行する処理が実装されているのではなく、
        DataGridViewの挙動自体がそのようになってしまっていると考えています)

    1回目のダイアログでの設定内容は保持された状態で2回目のダイアログが表示されるので、
    下手にフラグなどで1回目2回目を管理しようとして逆に設定できなくなるよりはよいと現状維持しておりますが、
    やはり挙動としてよくなく、できれば改善したいので、お知恵を拝借できればと思います。
    何か良い方法をご存知の方はいらっしゃいませんでしょうか。

    WindowsFormアプリケーションを、VisualStudio 2015、.NET Framework 4.5の環境で作成しております。

    以上、よろしくお願いします。


    • 編集済み Toma1988 2020年7月7日 5:20
    2020年7月7日 5:15

回答

  • ProcessDataGridViewKeyで編集中でない時の0キー処理を無効にしてみる

    class DataGridViewEx : DataGridView
    {
        protected override bool ProcessDataGridViewKey(KeyEventArgs e)
        {
            if (e.KeyCode == Keys.D0 || e.KeyCode == Keys.NumPad0)
            {
                return false;
            }
            return base.ProcessDataGridViewKey(e);
        }
    }


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    • 編集済み gekkaMVP 2020年7月16日 4:42 リンクにゴミ
    • 回答としてマーク Toma1988 2020年8月5日 0:53
    2020年7月16日 3:54

すべての返信

  • ダイアログを表示したあと、EndEdit を BeginInvoke するとかどうでしょう?

            private void dataGridView1_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e) {
                if (e.ColumnIndex == 1) {
                    using (var dlg = new DlgForm()) {
                        dlg.ShowDialog(this);
                    }
                    BeginInvoke((Action)(() => { dataGridView1.EndEdit(); }));
                }
            }
    

    2020年7月7日 12:54
  • KOZ6.0さん
    回答ありがとうございます。

    編集モードの開始をキャンセルするのではなく、
    開始直後に終了させるというということですね。
    たしかにやりたいこととしては同じになりますので、
    キャンセルで問題が起きるのであれば、それで対処できるかもしれません。
    提示された処理で現在の処理に問題が起きないか試してみます。

    2020年7月13日 0:08
  • Toma1988さん、こんにちは。フォーラムオペレーターのHarukaです。
    MSDNフォーラムにご投稿くださいましてありがとうございます。

    ご説明に基づいて、セルを編集した後にcellbegineditイベントの発生を停止する必要があります。
    datagrdiviewcell.readonlyプロパティを使用することをお勧めします。

    次のコード例をご参照いただければと思います。
    public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
    
            private void dataGridView1_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
            {
                string msg = String.Format("Editing Cell at ({0}, {1})",e.ColumnIndex, e.RowIndex);
                Console.WriteLine(msg);
               
            }
            private void Form1_Load(object sender, EventArgs e)
            {
                DataTable table = new DataTable();
                table.Columns.Add("Name");
                table.Columns.Add("Id");
                table.Columns.Add("Age");
                table.Rows.Add("test1","1001","24");
                table.Rows.Add("test2", "1002", "25");
                table.Rows.Add("test3", "1003", "26");
                dataGridView1.DataSource = table;
            }
    
            private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
            {
                dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].ReadOnly = true;
                dataGridView1.Refresh();
            }
    }
    

    テスト結果


    お役に立てれば幸いです。
    どうぞよろしくお願いいたします。

    MSDN/ TechNet Community Support Haruka
    ~参考になった投稿には「回答としてマーク」をご設定ください。なかった場合は「回答としてマークされていない」も設定できます。同じ問題で後から参照した方が、情報を見つけやすくなりますので、 ご協力くださいますようお願いいたします。また、MSDNサポートに賛辞や苦情がある場合は、MSDNFSF@microsoft.comまでお気軽にお問い合わせください。~

    2020年7月14日 6:09
    モデレータ
  • KOZ6.0さん

    回答いただいた内容ですと、少々うまくいかない部分が出てしまいました。
    EndEditですと入力が確定されてしまうため、0が入力されて確定された、となってしまいました。

    これは最初の質問の段階で記載していなかったのですが、
    ダイアログでキャンセルが選択された場合はデータを変更しないで終了することと、
    初回のセルデータ変更時にデータ変更がされたという状態を保持するとしているので、
    0確定となってしまうとよろしくない部分がありました。

    何かしらのフラグを用意すれば対処できるとは思いますので、
    良い方法がないか検討してみようと思います。

    2020年7月15日 23:42
  • Harukaさん
    回答ありがとうございます。

    頂いたコードで気になる点があるのですが、
    初回の変更時点でreadonlyにすれば編集ができなくなるので、
    2回目のCellBeginEditの発生を抑えることができると思いますが、
    再度そのセルを編集しようとしても、readonlyのままでは編集できなくなりませんか?
    一通りのイベント処理が完了し、ユーザーが操作する段階に戻った時点で設定を戻せばよいかと思いますが。

    まだ、実際には試してはいませんので、これから確認したいと思います。

    2020年7月16日 0:50
  • ProcessDataGridViewKeyで編集中でない時の0キー処理を無効にしてみる

    class DataGridViewEx : DataGridView
    {
        protected override bool ProcessDataGridViewKey(KeyEventArgs e)
        {
            if (e.KeyCode == Keys.D0 || e.KeyCode == Keys.NumPad0)
            {
                return false;
            }
            return base.ProcessDataGridViewKey(e);
        }
    }


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    • 編集済み gekkaMVP 2020年7月16日 4:42 リンクにゴミ
    • 回答としてマーク Toma1988 2020年8月5日 0:53
    2020年7月16日 3:54
  • あのコードだけだと値は変わらないと思うのですが、0が確定されます?

    変わったのなら、戻す処理を EndEdit の後に入れておけばいいのではないでしょうか。

    2020年7月16日 4:33
  • KOZ6.0さん

    頂いたコードそのままでは0確定されませんでした。
    確認が不十分で申し訳ありません。

    今回のCellBeginEditが2回発生する件について、
    現象の再現に必要最小限のもののみに削ったコードを作成しており、
    CellBeginEdit内のダイアログ表示は直接関係がなさそうだったためそれを削除したもので試しておりました。
    Dialogを表示することで(ActiveControlが変わるから?)0が確定されないようでした。

    今回の問題個所についてはこれで対応できそうです。

    2020年7月16日 11:21
  • gekkaさん
    回答ありがとうございます。

    頂いたコードで2重に発生していたCellBeginEditが発生しなくなりました。
    ここでの0の無効化がほかに影響ないかだけ確認出来たら、
    今まで使用していたグリッドを置き換えて対応できそうです。

    2020年7月16日 11:58
  • Toma1988さん、こんにちは。フォーラムオペレーターのHarukaです。
    ご返信いただきありがとうございます。

    まずコードを試して、ご要件を満たしているかどうかを確認することをお勧めします。
    私の考えでは、datagridviewでセルの値が変更されたときに、そのセルをreadonlyに設定します。
    このようにして、cellbegineditイベントが2回目にトリガーされないことを保証できます。
    私の説明がお役に立てば幸いです。

    どうぞよろしくお願いいたします。

    MSDN/ TechNet Community Support Haruka
    ~参考になった投稿には「回答としてマーク」をご設定ください。なかった場合は「回答としてマークされていない」も設定できます。同じ問題で後から参照した方が、情報を見つけやすくなりますので、 ご協力くださいますようお願いいたします。また、MSDNサポートに賛辞や苦情がある場合は、MSDNFSF@microsoft.comまでお気軽にお問い合わせください。~

    2020年7月20日 6:25
    モデレータ