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

DataGridViewのCheck状態の変更

環境/言語:[OS : Windows XP / 言語 : C# / .NET Framework : 2.0]
分類:[.NET]

2009/12/17(Thu) 01:56:53 編集(投稿者)

はじめまして、いつも参考にさせて頂いております。

こちらの
DataGridViewの列にチェックボックスを表示する
http://dobon.net/cgi-bin/pc/tb.php/datagridview/datagridviewcheckboxcolumn.html

を参考にDataGridViewにチェックボックスが表示されるように実装しました。

このチェックボックスは特定の条件を満たした行のチェックを行った場合に
警告を出して、自動で外す。
という形にしたいのですがCurrentCellDirtyStateChangedイベント内で
DataGridView1.CurrentCell.Value = false;
としてみたのですがフォーカスが外れない限りチェックが外れない状態です。

上記の処理を実装する方法がありましたら、ご教授頂けますでしょうか
よろしくお願い致します。
■No26073に返信(しらいわさんの記事)
>http://dobon.net/cgi-bin/pc/tb.php/datagridview/datagridviewcheckboxcolumn.html
そのアドレスはこちらで見れないのですが、
http://dobon.net/vb/dotnet/datagridview/datagridviewcheckboxcolumn.html
であれば、コミットするように解説されていると思います。
よく読んで、理解してからプログラミングしてください。
2009/12/19(Sat) 01:05:17 編集(投稿者)

るしぇ様

ご返答、ありがとうございます。
ご指摘のアドレスで間違い有りません。
間違ってトラックバック用URLを使用したみたいです。


CurrentCellDirtyStateChangedイベントで
>DataGridView1.CurrentCell.Value = false;
の直後に
>DataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
を使いコミットして居るのですが
やはり、フォーカスが変わらないとチェックが外れません。

また、CellValueChangedイベントで
>DataGridView1.CurrentCell.Value = false;
>DataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
を行うとコミット部分で無限ループしてしまうので
コミット部分をコメントアウトしてみましたが
やはり、フォーカスが変わらないとチェックが外れない状態です。
お疲れ様です。

CellEndEditではいかがでしょうか?

Public Class Form_CheckBoxColumnTest
    Inherits Form

    Dim WithEvents DataGridView1 As New DataGridView

    Protected Overrides Sub OnLoad(ByVal e As System.EventArgs)
        With Me.DataGridView1
            .Columns.Add(New DataGridViewCheckBoxColumn)
            .Columns.Add(New DataGridViewTextBoxColumn)
            .RowCount = 10
            .Dock = DockStyle.Fill
        End With
        Me.Controls.Add(Me.DataGridView1)
        MyBase.OnLoad(e)
    End Sub

    ' TextBoxCellに何か入力するとCheckedに変更する
    Private Sub DataGridView1_CellEndEdit(ByVal sender As Object, _
            ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DataGridView1.CellEndEdit
        With Me.DataGridView1
            If .Columns(e.ColumnIndex).GetType Is GetType(DataGridViewTextBoxColumn) Then
                Dim checkboxcell As DataGridViewCell = .Item(0, e.RowIndex)
                If Convert.ToString(.Item(e.ColumnIndex, e.RowIndex).Value) <> "" Then
                    checkboxcell.Value = True
                Else
                    checkboxcell.Value = False
                End If
            End If
        End With
    End Sub

End Class
H.K.R.様

ご返答、ありがとうございます

早速、CellEndEditイベントを追加して見ましたが
コチラはセルからフォーカスが外れた後に発生するイベントのようで
やはり、フォーカスを外さなければいけませんでした。
■No26073に返信(しらいわさんの記事)
> このチェックボックスは特定の条件を満たした行のチェックを行った場合に
> 警告を出して、自動で外す。

これでどうでしょう。

using System;
using System.Windows.Forms;
using System.Data;
using System.Drawing;

public partial class Form1 : Form
{
    public static void Main()
    {
        Application.Run(new Form1());
    }

    DataGridView dgv = new DataGridView();
    DataTable tbl = new DataTable();
    DataColumn colID;
    public Form1()
    {
        colID = tbl.Columns.Add("ID", typeof(int));
        tbl.Columns.Add("Check", typeof(bool));
        tbl.Columns.Add("Name", typeof(string));

        colID.ReadOnly = true;
        tbl.PrimaryKey = new DataColumn[] { colID };

        tbl.Rows.Add(10, false, "色は匂へど");
        tbl.Rows.Add(20, false, "散りぬるを");
        tbl.Rows.Add(30, false, "我が世誰そ");
        tbl.Rows.Add(40, true, "常ならむ");
        tbl.Rows.Add(50, true, "有為の奥山");
        tbl.Rows.Add(60, true, "今日越えて");
        tbl.Rows.Add(70, false, "浅き夢見じ");
        tbl.Rows.Add(80, false, "酔ひもせず");

        dgv.AutoGenerateColumns = true;
        dgv.AllowUserToAddRows = false;
        dgv.Dock = DockStyle.Fill;
        dgv.DataSource = tbl;
        dgv.EditMode = DataGridViewEditMode.EditOnEnter;
        Controls.Add(dgv);
        Shown += delegate { dgv.AutoResizeColumns(); };
        dgv.CurrentCellDirtyStateChanged += new EventHandler(dgv_CurrentCellDirtyStateChanged);
    }

    void dgv_CurrentCellDirtyStateChanged(object sender, EventArgs e)
    {
        Point cell = dgv.CurrentCellAddress;
        if (特定の条件(cell.X, cell.Y))
        {
            if (dgv.IsCurrentCellDirty)
            {
                MessageBox.Show("警告");

                // 値キャンセル
                dgv.RefreshEdit();

                // 値確定
                // dgv.CommitEdit(DataGridViewDataErrorContexts.Commit);
            }
        }
    }

    public bool IsCheckBoxColumn(int col)
    {
        return (dgv.Columns[col].Name == "Check");
    }

    public bool 特定の条件(int colIndex, int rowIndex)
    {
        // ID が 40 未満のチェックボックス列ならば true
        DataGridViewRow row = dgv.Rows[rowIndex];
        DataRowView rowView = (DataRowView)row.DataBoundItem;
        if (rowView == null || rowView.IsNew || !IsCheckBoxColumn(colIndex))
        {
            return false;
        }
        else
        {
            return (int)rowView["ID"] < 40;
        }
    }
}
2009/12/19(Sat) 12:47:09 編集(投稿者)

■No26098に返信(しらいわさんの記事)
DataGridView の編集中は、編集中のセルと同じ大きさのセルが1つだけ
前面に表示されて編集モードの状態になる。。。というのが設計の基本に
なってるはず。

今回の場合、DataGridView のデータは更新されても、編集用の前面に
表示されたセルの方がそのままになってるんじゃないかと予想してます。

魔界の仮面弁士さんのように RefreshEdit を使うか、
http://social.msdn.microsoft.com/Forums/ja-JP/csharpgeneralja/thread/bca22808-2e8a-43df-95b3-d9c14682ed8c
のように EndEdit を使うか、とにかく編集モードを終わらせて
編集用セルと同期を取る必要があるみたいですね。
魔界の仮面弁士 様
るしぇ 様

ご回答、サンプルの提示、ありがとうございます。
RefreshEdit と EndEdit の両方で期待した動作が実現する事を確認出来ました。
それぞれの仕様を読んでどちらを使うか決めて、実装したいと思います。

ご教授、ありがとうございました。
解決済み!

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