やりたいこと
- Flag1 が true → false に変更される場合に確認ダイアログを表示し、キャンセルならば Flag1 を true に戻したい。
- 別のセルにフォーカスが移らなくても、チェックボックスのチェックが外された直後に確認ダイアログを表示したい。
概要
- DataGridViewとデータクラスの間にUndo機能を提供するクラスを挟む。
- CurrentCellDirtyStateChangedイベントで、CommitEditを呼ぶ。
実装
データクラス
public class Row
{
public string Name { get; set; }
public bool Flag1 { get; set; }
public bool Flag2 { get; set; }
}
Undo機能を提供するクラス
public class RowViewModel
{
Row raw;
bool previousFlag1;
public RowViewModel(Row raw)
{
this.raw = raw;
this.previousFlag1 = this.raw.Flag1;
}
public string Name
{
get { return raw.Name; }
set { raw.Name = value; }
}
public bool Flag1
{
get { return raw.Flag1; }
set
{
previousFlag1 = raw.Flag1;
raw.Flag1 = value;
}
}
public bool Flag2
{
get { return raw.Flag2; }
set { raw.Flag2 = value; }
}
public bool Flag1_CanUndo()
{
return previousFlag1 && !raw.Flag1;
}
public void UndoFlag1()
{
raw.Flag1 = previousFlag1;
}
}
ヘルパー
public class PocoHelper<T>
{
// プロパティからプロパティ名を取得
public static string GetName<TKey>(System.Linq.Expressions.Expression<Func<T, TKey>> e)
{
var member = (System.Linq.Expressions.MemberExpression)e.Body;
return member.Member.Name;
}
}
フォーム
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
dataGridView1.AutoGenerateColumns = false;
rowViewModelBindingSource.DataSource = Enumerable.Range(1, 5)
.Select(i => new Row() { Name = "row" + i })
.Select(x => new RowViewModel(x))
.ToArray();
}
private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex < 0) return;
var dgv = (DataGridView)sender;
if (dgv.Columns[e.ColumnIndex].DataPropertyName == PocoHelper<RowViewModel>.GetName(x => x.Flag1))
{
var row = (RowViewModel)dgv.Rows[e.RowIndex].DataBoundItem;
if (row.Flag1_CanUndo())
{
var msg = "Flag1 を true → false に変更して構いませんか?";
if (MessageBox.Show(msg, "確認", MessageBoxButtons.OKCancel) == DialogResult.Cancel)
{
row.UndoFlag1();
dgv.RefreshEdit();
}
}
}
}
private void dataGridView1_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
var dgv = (DataGridView)sender;
if (dgv.CurrentCell.OwningColumn.DataPropertyName == PocoHelper<RowViewModel>.GetName(x => x.Flag1))
{
dgv.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
}
}