DataSource 为 DatagridView 绑定数据时设置 DataGridViewRow.Tag 的值
Setting value for DataGridViewRow.Tag when data binding by DataSource for DatagridView
我想在数据绑定时为 DataGridViewRow.Tag
设置一个值,但我不知道该怎么做?
我试过 DataRow row = table.NewRow();
但是行没有标签。
如何在 binding DataGridView
到 table 时设置 DataGridViewRow.Tag 的值(例如)?或者不可能?
编辑 1:
这是我正在使用的代码:
var table = new DataTable();
table.Columns.Add("Title", typeof(string));
table.Columns.Add("URL", typeof(string));
table.Columns.Add("Read Later", typeof(bool));
foreach (XElement node in nodes)
{
Helper.CheckNode(node);
var id = node.Attribute("id").Value;
var url = node.Element("path").Value;
var comment = node.Element("title").Value;
var readlater = node.Attribute("readLater")?.Value.ToString() == "1";
var row = table.NewRow();
row.ItemArray = new object[] { url, comment, readlater };
table.Rows.Add(row);//Edit2
}
dataGridView1.DataSource = table;
我正在尝试为该行设置一个标记以在 CellClick 事件中使用它:
var cRow = dataGridView1.Rows[e.RowIndex];
var id = cRow.Tag.ToString();
将数据与其显示方式分开
使用 DataGridView 时,直接访问单元格和列很少是个好主意。使用 DataGridView.DataSource
.
更容易
在现代编程中,倾向于将数据(= 模型)与数据显示方式(= 视图)分开。要将这两个项目粘合在一起,需要一个适配器 class,通常称为视图模型。这三项简称为MVVM。
使用DataGridView.DataSource显示数据
显然,如果操作员单击一个单元格,您想读取该单元格行的标记值,以获取一些额外信息,一些 Id。
显示的这一行是一些数据的显示。显然,此数据的部分功能是访问此 Id。你不应该把这些信息放在视图中,你应该把它放在模型中。
class MyWebPage // TODO: invent proper identifier
{
public int Id {get; set;}
public string Title {get; set;}
public string Url {get; set;}
public bool ReadLater {get; set;}
... // other properties
}
显然,您有一种方法可以从 nodes
的序列中获取要显示的数据。将获取此数据(=模型)与显示它(=视图)分开:
IEnumerable<MyWebPage> FetchWebPages(...)
{
...
foreach (XElement node in nodes)
{
Helper.CheckNode(node);
bool readLater = this.CreateReadLater(node);
yield return new MyWebPage
{
Id = node.Attribute("id").Value,
Url = node.Element("path").Value,
Title = node.Element("title").Value,
ReadLater = this.CreateReadLater(node),
};
}
}
我不知道节点“ReadLater”中有什么,显然你知道如何将它转换为布尔值。
bool CreateReadLater(XElement node)
{
// TODO: implement, if null return true; if not null ...
// out of scope of this question
}
对于每个要显示的 属性,您都创建一个 DataGridViewColumn。 属性 DataPropertyName defines which property should be shown in the column. Use DefaultCellStyle 如果标准 ToString 不足以正确显示值,例如,定义小数点后的位数,或将负值着色为红色。
您可以使用 visual studio 设计器执行此操作,或者您可以在构造函数中执行此操作:
public MyForm
{
InitializeComponents();
this.dataGridViewColumnTitle.DataPropertyName = nameof(MyWebPage.Title);
this.dataGridViewColumnUrl.DataPropertyName = nameof(MyWebPage.Url);
...
}
您不想显示 ID,因此没有此列。
现在要显示数据,您所要做的就是将列表分配给数据源:
this.dataGrieViewWebPages.DataSource = this.FetchWebPages().ToList();
这只是展示。如果操作员可以更改显示的值,并且您想要访问更改后的值,则应将项目放在实现接口 IBindingList 的对象中,例如,使用 class(惊喜!)BindingList<T>
:
private BindingList<MyWebPage> DisplayedWebPages
{
get => (BindingList<MyWebPage>)this.dataGrieViewWebPages.DataSource;
set => this.dataGrieViewWebPages.DataSource = value;
}
初始化:
private void DisplayWebPages()
{
this.DisplayedWebPages = new BindingList<MyWebPage>(this.FetchWebPages.ToList());
}
很快!显示所有网页。操作员所做的每项更改:添加/删除/编辑行都会在 DisplayedWebPages 中自动更新。
如果要访问当前选中的网页:
private MyWebPage CurrentWebPage =>(MyWebPage)this.dataGrieViewWebPages.CurrentRow?.DataBoundItem;
private IEnumerable<MyWebPage> SelectedWebPages =>
this.dataGrieViewWebPages.SelectedRows
.Cast<DataGridViewRow>()
.Select(row => row.DataBoundItem)
.Cast<MyWebPage>();
显然,每当操作员单击一个单元格时,您都希望对显示在单元格行中的网页 ID 执行某些操作。
- View: 显示单元格和行
- ViewModel:操作员单击单元格时做出反应
- 模型必须做的动作
响应单元格点击:获取 Id
我们已经处理了上面的视图。 ViewModel 是事件处理程序:
void OnDatGridViewCellClicked(object sender, DataGridViewCellEventArgs e)
{
// use the eventArgs to fetch the row, and thus the WebPage:
MyWebPage webPage = (MyWebPage)this.dataGridViewWebPages.Rows[e.RowIndow].DataBoundItem;
this.ProcessWebPage(webPage);
}
ProcessWebPage 通常是模型中的一个方法 class:
public void ProcessWebPage(MyWebPage webPage)
{
// Do what you need to do if the operator clicks the cell, for example:
int webPageId = webPage.Id;
...
}
结论:模型与视图分离的优点
对了,你看到所有的ViewModel方法都是一行的了吗?只有您的模型方法 FetchWebPages
和 ProcessWebPage 包含多行。
因为您将视图与模型分开,所以对模型或视图的更改将相当简单:
- 如果您想以 Json 格式或数据库而不是 XML 格式存储数据,您的视图将不会改变
- 如果您不想对单元格点击做出反应,而是对“确定按钮”点击做出反应,那么您的模型将不会改变。如果您决定显示更多或更少的列,您的模型也不必更改
- 因为您将模型与视图分开,模型可以在没有表单的情况下进行单元测试。您还可以使用仅填充测试值的模型来测试视图。
我想在数据绑定时为 DataGridViewRow.Tag
设置一个值,但我不知道该怎么做?
我试过 DataRow row = table.NewRow();
但是行没有标签。
如何在 binding DataGridView
到 table 时设置 DataGridViewRow.Tag 的值(例如)?或者不可能?
编辑 1:
这是我正在使用的代码:
var table = new DataTable(); table.Columns.Add("Title", typeof(string)); table.Columns.Add("URL", typeof(string)); table.Columns.Add("Read Later", typeof(bool)); foreach (XElement node in nodes) { Helper.CheckNode(node); var id = node.Attribute("id").Value; var url = node.Element("path").Value; var comment = node.Element("title").Value; var readlater = node.Attribute("readLater")?.Value.ToString() == "1"; var row = table.NewRow(); row.ItemArray = new object[] { url, comment, readlater }; table.Rows.Add(row);//Edit2 } dataGridView1.DataSource = table;
我正在尝试为该行设置一个标记以在 CellClick 事件中使用它:
var cRow = dataGridView1.Rows[e.RowIndex]; var id = cRow.Tag.ToString();
将数据与其显示方式分开
使用 DataGridView 时,直接访问单元格和列很少是个好主意。使用 DataGridView.DataSource
.
在现代编程中,倾向于将数据(= 模型)与数据显示方式(= 视图)分开。要将这两个项目粘合在一起,需要一个适配器 class,通常称为视图模型。这三项简称为MVVM。
使用DataGridView.DataSource显示数据
显然,如果操作员单击一个单元格,您想读取该单元格行的标记值,以获取一些额外信息,一些 Id。
显示的这一行是一些数据的显示。显然,此数据的部分功能是访问此 Id。你不应该把这些信息放在视图中,你应该把它放在模型中。
class MyWebPage // TODO: invent proper identifier
{
public int Id {get; set;}
public string Title {get; set;}
public string Url {get; set;}
public bool ReadLater {get; set;}
... // other properties
}
显然,您有一种方法可以从 nodes
的序列中获取要显示的数据。将获取此数据(=模型)与显示它(=视图)分开:
IEnumerable<MyWebPage> FetchWebPages(...)
{
...
foreach (XElement node in nodes)
{
Helper.CheckNode(node);
bool readLater = this.CreateReadLater(node);
yield return new MyWebPage
{
Id = node.Attribute("id").Value,
Url = node.Element("path").Value,
Title = node.Element("title").Value,
ReadLater = this.CreateReadLater(node),
};
}
}
我不知道节点“ReadLater”中有什么,显然你知道如何将它转换为布尔值。
bool CreateReadLater(XElement node)
{
// TODO: implement, if null return true; if not null ...
// out of scope of this question
}
对于每个要显示的 属性,您都创建一个 DataGridViewColumn。 属性 DataPropertyName defines which property should be shown in the column. Use DefaultCellStyle 如果标准 ToString 不足以正确显示值,例如,定义小数点后的位数,或将负值着色为红色。
您可以使用 visual studio 设计器执行此操作,或者您可以在构造函数中执行此操作:
public MyForm
{
InitializeComponents();
this.dataGridViewColumnTitle.DataPropertyName = nameof(MyWebPage.Title);
this.dataGridViewColumnUrl.DataPropertyName = nameof(MyWebPage.Url);
...
}
您不想显示 ID,因此没有此列。
现在要显示数据,您所要做的就是将列表分配给数据源:
this.dataGrieViewWebPages.DataSource = this.FetchWebPages().ToList();
这只是展示。如果操作员可以更改显示的值,并且您想要访问更改后的值,则应将项目放在实现接口 IBindingList 的对象中,例如,使用 class(惊喜!)BindingList<T>
:
private BindingList<MyWebPage> DisplayedWebPages
{
get => (BindingList<MyWebPage>)this.dataGrieViewWebPages.DataSource;
set => this.dataGrieViewWebPages.DataSource = value;
}
初始化:
private void DisplayWebPages()
{
this.DisplayedWebPages = new BindingList<MyWebPage>(this.FetchWebPages.ToList());
}
很快!显示所有网页。操作员所做的每项更改:添加/删除/编辑行都会在 DisplayedWebPages 中自动更新。
如果要访问当前选中的网页:
private MyWebPage CurrentWebPage =>(MyWebPage)this.dataGrieViewWebPages.CurrentRow?.DataBoundItem;
private IEnumerable<MyWebPage> SelectedWebPages =>
this.dataGrieViewWebPages.SelectedRows
.Cast<DataGridViewRow>()
.Select(row => row.DataBoundItem)
.Cast<MyWebPage>();
显然,每当操作员单击一个单元格时,您都希望对显示在单元格行中的网页 ID 执行某些操作。
- View: 显示单元格和行
- ViewModel:操作员单击单元格时做出反应
- 模型必须做的动作
响应单元格点击:获取 Id
我们已经处理了上面的视图。 ViewModel 是事件处理程序:
void OnDatGridViewCellClicked(object sender, DataGridViewCellEventArgs e)
{
// use the eventArgs to fetch the row, and thus the WebPage:
MyWebPage webPage = (MyWebPage)this.dataGridViewWebPages.Rows[e.RowIndow].DataBoundItem;
this.ProcessWebPage(webPage);
}
ProcessWebPage 通常是模型中的一个方法 class:
public void ProcessWebPage(MyWebPage webPage)
{
// Do what you need to do if the operator clicks the cell, for example:
int webPageId = webPage.Id;
...
}
结论:模型与视图分离的优点
对了,你看到所有的ViewModel方法都是一行的了吗?只有您的模型方法 FetchWebPages
和 ProcessWebPage 包含多行。
因为您将视图与模型分开,所以对模型或视图的更改将相当简单:
- 如果您想以 Json 格式或数据库而不是 XML 格式存储数据,您的视图将不会改变
- 如果您不想对单元格点击做出反应,而是对“确定按钮”点击做出反应,那么您的模型将不会改变。如果您决定显示更多或更少的列,您的模型也不必更改
- 因为您将模型与视图分开,模型可以在没有表单的情况下进行单元测试。您还可以使用仅填充测试值的模型来测试视图。