以下の解決策は、MSDNのドキュメントに注いで、こことCodeProjectのいくつかの接線スレッドに少し運があったことから生まれました。
アイデアは、ContentClickとともにトリガーされるハンドラーを含むDataGridViewCheckBoxCellから派生したクラスを作成することです。これは、1つのDataGridViewにとって多くのオーバーヘッドのように見えるかもしれませんが、私のアプリケーションには多くのDataGridViewがあるため、このコードは再利用可能であり、時間を節約できます。
/// <summary>
/// DataGridView cell class for check box cells with a OnContentClick event handler.
/// </summary>
public class DataGridViewEventCheckBoxCell : DataGridViewCheckBoxCell
{
/// <summary>
/// Event handler for OnContentClick event.
/// </summary>
protected EventHandler<DataGridViewCellEventArgs> ContentClickEventHandler { get; set; }
/// <summary>
/// Empty constructor. Required. Used by Clone mechanism
/// </summary>
public DataGridViewEventCheckBoxCell()
: base()
{ }
/// <summary>
/// Pass through constructor for threeState parameter.
/// </summary>
/// <param name="threeState">True for three state check boxes, True, False, Indeterminate.</param>
public DataGridViewEventCheckBoxCell(bool threeState)
: base(threeState)
{ }
/// <summary>
/// Constructor to set the OnContentClick event handler.
/// Signature for handler should be (object sender, DataGridViewCellEventArgs e)
/// The sender will be the DataGridViewCell that is clicked.
/// </summary>
/// <param name="handler">Handler for OnContentClick event</param>
/// <param name="threeState">True for three state check boxes, True, False, Indeterminate.</param>
public DataGridViewEventCheckBoxCell(EventHandler<DataGridViewCellEventArgs> handler, bool threeState)
: base(threeState)
{
ContentClickEventHandler = handler;
}
/// <summary>
/// Clone method override. Required so CheckEventHandler property is cloned.
/// Individual DataGridViewCells are cloned from the DataGridViewColumn.CellTemplate
/// </summary>
/// <returns></returns>
public override object Clone()
{
DataGridViewEventCheckBoxCell clone = (DataGridViewEventCheckBoxCell)base.Clone();
clone.ContentClickEventHandler = ContentClickEventHandler;
return clone;
}
/// <summary>
/// Override implementing OnContentClick event propagation
/// </summary>
/// <param name="e">Event arg object, which contains row and column indexes.</param>
protected override void OnContentClick(DataGridViewCellEventArgs e)
{
base.OnContentClick(e);
if (ContentClickEventHandler != null)
ContentClickEventHandler(this, e);
}
/// <summary>
/// Override implementing OnContentDoubleClick event propagation
/// Required so fast clicks are handled properly.
/// </summary>
/// <param name="e">Event arg object, which contains row and column indexes.</param>
protected override void OnContentDoubleClick(DataGridViewCellEventArgs e)
{
base.OnContentDoubleClick(e);
if (ContentClickEventHandler != null)
ContentClickEventHandler(this, e);
}
}
列クラスからこのセルクラスを参照できるようにしたかったので、DataGridViewCheckBoxColumnから派生したクラスも実装しました。
/// <summary>
/// DataGridView column class for a check box column with cells that have an OnContentClick handler.
/// </summary>
public class DataGridViewEventCheckBoxColumn : DataGridViewCheckBoxColumn
{
/// <summary>
/// Empty constructor. Pass through to base constructor
/// </summary>
public DataGridViewEventCheckBoxColumn()
: base()
{ }
/// <summary>
/// Pass through to base constructor with threeState parameter
/// </summary>
/// <param name="threeState">True for three state check boxes, True, False, Indeterminate.</param>
public DataGridViewEventCheckBoxColumn(bool threeState)
: base(threeState)
{ }
/// <summary>
/// Constructor for setting the OnContentClick event handler for the cell template.
/// Note that the handler will be called for all clicks, even if the DataGridView is ReadOnly.
/// For the "new" state of the checkbox, use the EditedFormattedValue property of the cell.
/// </summary>
/// <param name="handler">Event handler for OnContentClick.</param>
/// <param name="threeState">True for three state check boxes, True, False, Indeterminate.</param>
public DataGridViewEventCheckBoxColumn(EventHandler<DataGridViewCellEventArgs> handler, bool threeState)
: base(threeState)
{
CellTemplate = new DataGridViewEventCheckBoxCell(handler, threeState);
}
}
無関係なコードを削除して、次のように使用しています。
public void AddCheckBoxColumn(DataGridView grid, EventHandler<DataGridViewCellEventArgs> handler, bool threeState)
{
grid.Columns.Add(new DataGridViewEventCheckBoxColumn(handler, threeState));
}
列クラスを削除することができ、次のように使用できます。
public void AddCheckBoxColumn(DataGridView grid, EventHandler<DataGridViewCellEventArgs> handler, bool threeState)
{
DataGridViewCheckBoxColumn column = new DataGridViewCheckBoxColumn(threeState);
column.CellTemplate = new DataGridViewEventCheckBoxCell(handler, threeState);
grid.Columns.Add(column);
}
これがサンプルのイベントハンドラーです。データグリッド内の別の列の状態は、この列の値と、条件付きでWasReleasedプロパティのいくつかの状態情報に基づいて更新されます。DataGridViewのデータソースは標本オブジェクトのコレクションであるため、各行のDataBoundItemは標本です。Specimenクラスはアプリケーション固有ですが、この列に表示されるOnHoldプロパティがあります。IsReleased、別の列に表示されます。とWasReleased。
public static void OnHoldCheckClick(object sender, DataGridViewCellEventArgs e)
{
if (sender is DataGridViewEventCheckBoxCell)
{
DataGridViewEventCheckBoxCell cell = sender as DataGridViewEventCheckBoxCell;
if (!cell.ReadOnly)
{
// The rows in the DataGridView are bound to Specimen objects
Specimen specimen = (Specimen)cell.OwningRow.DataBoundItem;
// Modify the underlying data source
if ((bool)cell.EditedFormattedValue)
specimen.IsReleased = false;
else if (specimen.WasReleased)
specimen.IsReleased = true;
// Then invalidate the cell in the other column to force it to redraw
DataGridViewCell releasedCell = cell.OwningRow.Cells["IsReleased"];
cell.DataGridView.InvalidateCell(releasedCell);
}
}
}
良いスタイルは、おそらくイベントハンドラーのコードの一部をSpecimenクラスのメソッドにプッシュダウンするでしょう。