dポイントプレゼントキャンペーン実施中!

C# WinForm のDataGridView CellValueChangeイベントが発火する条件について、ユーザーがセルを操作して値を変更した場合は当然の事で、プログラム内部でDataGridViewCellの値を編集した場合も同様です。しかし、データソースにDataTableをバインドし、DataTableの値を変えても発火してくれませんでした。(セルの値ら追従して変わってぬれる)データソースを変更した際にもCellValueChangeのイベントを発火させる方法はないでしょうか。CellValueChangeを使う事にこだわりはありませんが、実現したい事としましては、DataTableで変更された対象セルの背景色を変えたいになります。どうぞ宜しくお願い致します。

A 回答 (3件)

ANo.2です。


文字数が足らなくなったので連投します。

DataTableを利用している場合、DataTableのイベントで捕捉して制御することが可能かと思います。

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

namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
private BindingSource bindingSource;
private DataTable dataList;

public Form1()
{
InitializeComponent();

dataList = new DataTable();
dataList.Columns.AddRange(new DataColumn[] { new DataColumn("Column1"), new DataColumn("Column2") });
var row = dataList.NewRow();
row["Column1"] = "aaa";
row["Column2"] = "aaaa";
dataList.Rows.Add(row);
row = dataList.NewRow();
row["Column1"] = "bbb";
row["Column2"] = "bbbb";
dataList.Rows.Add(row);
row = dataList.NewRow();
row["Column1"] = "ccc";
row["Column2"] = "cccc";
dataList.Rows.Add(row);

dataList.ColumnChanged += (sender, e) =>
{
var rowIndex = dataList.Rows.IndexOf(e.Row);
rowIndex = rowIndex == -1 ? dataList.Rows.Count : rowIndex;
dgv.Rows[rowIndex].Cells[e.Column.ColumnName].Style.BackColor = Color.Red;
};

bindingSource = new BindingSource();
bindingSource.DataSource = dataList;
dgv.DataSource = bindingSource;
}

private void datachangeButton_Click(object sender, EventArgs e)
{
dataList.Rows[2]["Column2"] = "dddd";
dgv.Refresh();
}
}
}
    • good
    • 0
この回答へのお礼

コードまで載せて下さりありがとうございます。
BaindingListの方とても参考になりました。今回はDataTableを利用するやり方にしたいと思います。やはりDataGridViewとDataTableの整合は行列でやるしかないんですね。DataGridViewでソートやフィルターをすると整合が取れなくなるので上手いこと実装したいと思いますが、その他注意点などありましたらご教授頂けると幸いです。ほぼベストアンサーに近い回答ですが、あと数日待ってからにさせて下さい。

お礼日時:2021/05/21 19:53

> BindingSourceのデータソースから取り出したDataTableに変更を加わえ


> ると、イベントが発火してくれるという理解で良いでしょうか?

CellValueChangeイベントが発火するかという問いならば違います。
CellValueChangeイベントはあくまでDataGridViewオブジェクトを操作した時に発生するイベントであり、データが変更されたからといって発生するものではありません。

BindingSource、BindingList、INotifyPropertyChangedを利用して値変更の通知をうけてBindingListオブジェクトのイベントを発火させ、何が通知されたかによって制御することで実装することができます。

ただし、下記の点を考慮する必要があります。

まず、データとDataGridViewは別物であるということ。
データの変更通知としては、DataGridViewのどのセルが変わったかなんてどうもいいことなので、DataGridViewのどのセル、という判断は独自で実装する必要があります。

次に、BindingList<T>などに依存すること。
DataSet、DataTableの結果を丸々DataSourceとして設定して、DataRowStateなどを利用して変更された行かどうかなどの判定を行う実装をしている場合、適合することはできません。


using System;
using System.ComponentModel;
using System.Drawing;
using System.Runtime.CompilerServices;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
private BindingSource bindingSource;
private BindingList<Data> dataList;

public Form1()
{
InitializeComponent();

dataList = new BindingList<Data>()
{
new Data() { Column1 = "aaa", Column2 = "aaaa"},
new Data() { Column1 = "bbb", Column2 = "bbbb"},
new Data() { Column1 = "ccc", Column2 = "cccc"}
};
dataList.ListChanged += (sender, e) =>
{
if (e.ListChangedType != ListChangedType.ItemChanged)
{
return;
}
if (e.PropertyDescriptor.Name == "Column2")
{
dgv.Rows[e.NewIndex].Cells[1].Style.BackColor = Color.Red;
}
};

bindingSource = new BindingSource();
bindingSource.DataSource = dataList;
dgv.DataSource = bindingSource;
}

private void datachangeButton_Click(object sender, EventArgs e)
{
dataList[2].Column2 = "dddd";
dgv.Refresh();
}
}

class Data : INotifyPropertyChanged
{
private string column1 = string.Empty;

private string column2 = string.Empty;

public event PropertyChangedEventHandler PropertyChanged;

private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}

public string Column1
{
get
{
return this.column1;
}

set
{
if (value != this.column1)
{
this.column1 = value;
NotifyPropertyChanged();
}
}
}

public string Column2
{
get
{
return this.column2;
}

set
{
if (value != this.column2)
{
this.column2 = value;
NotifyPropertyChanged();
}
}
}
}
}
    • good
    • 0

値を変更してもDataGridViewオブジェクトの操作による変更ではないので、イベントは発火しません。



BindingSourceを介したバインドを検討してみてください。
https://docs.microsoft.com/ja-jp/dotnet/api/syst …
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。BindingSourceのデータソースから取り出したDataTableに変更を加わえると、イベントが発火してくれるという理解で良いでしょうか?

お礼日時:2021/05/21 06:24

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!