C#,从 DataGridView 填充 iTextSharp PDF 时出现空异常问题
C#, Null Exception Problem while Populating iTextSharp PDF from DataGridView
终极菜鸟的问候。
我正在使用 C# 在 WinForms 中为我的地质学家团队准备时间 sheet 计划程序,但在从 DataGridView 值填充 PDF 表时遇到问题。
我的计划中有一个每月的时间表。当您单击 Get Excel(我将其更改为 PDF)时,程序会根据 DataGridView 值创建一个 pdf 文件。如果您有 31 天的完整数据网格视图,则没有问题。但是当这个月有30天或者用户想在月底之前获取PDF时,它会给出空异常。
代码在这里。
#region Functions
DataTable MakeDataTable()
{
//Create time sheet table object
DataTable dtgdata = new DataTable();
//Define columns
dtgdata.Columns.Add("Date");
dtgdata.Columns.Add("Type of Work");
dtgdata.Columns.Add("Contract");
dtgdata.Columns.Add("Personnel ID");
#region PopulateData
string date_1 = dtgList.Rows[0].Cells[1].Value.ToString();
string date_2 = dtgList.Rows[1].Cells[1].Value.ToString();
string date_3 = dtgList.Rows[2].Cells[1].Value.ToString();
string date_4 = dtgList.Rows[3].Cells[1].Value.ToString();
string date_5 = dtgList.Rows[4].Cells[1].Value.ToString();
string date_6 = dtgList.Rows[5].Cells[1].Value.ToString();
string date_7 = dtgList.Rows[6].Cells[1].Value.ToString();
string date_8 = dtgList.Rows[7].Cells[1].Value.ToString();
string date_9 = dtgList.Rows[8].Cells[1].Value.ToString();
string date_10 = dtgList.Rows[9].Cells[1].Value.ToString();
string date_11 = dtgList.Rows[10].Cells[1].Value.ToString();
string date_12 = dtgList.Rows[11].Cells[1].Value.ToString();
string date_13 = dtgList.Rows[12].Cells[1].Value.ToString();
string date_14 = dtgList.Rows[13].Cells[1].Value.ToString();
string date_15 = dtgList.Rows[14].Cells[1].Value.ToString();
string date_16 = dtgList.Rows[15].Cells[1].Value.ToString();
string date_17 = dtgList.Rows[16].Cells[1].Value.ToString();
string date_18 = dtgList.Rows[17].Cells[1].Value.ToString();
string date_19 = dtgList.Rows[18].Cells[1].Value.ToString();
string date_20 = dtgList.Rows[19].Cells[1].Value.ToString();
string date_21 = dtgList.Rows[20].Cells[1].Value.ToString();
string date_22 = dtgList.Rows[21].Cells[1].Value.ToString();
string date_23 = dtgList.Rows[22].Cells[1].Value.ToString();
string date_24 = dtgList.Rows[23].Cells[1].Value.ToString();
string date_25 = dtgList.Rows[24].Cells[1].Value.ToString();
string date_26 = dtgList.Rows[25].Cells[1].Value.ToString();
string date_27 = dtgList.Rows[26].Cells[1].Value.ToString();
string date_28 = dtgList.Rows[27].Cells[1].Value.ToString();
string date_29 = dtgList.Rows[28].Cells[1].Value.ToString();
string date_30 = dtgList.Rows[29].Cells[1].Value.ToString();
string date_31 = dtgList.Rows[30].Cells[1].Value.ToString();
////////////////////////////////////////////////////////////
string work_1 = dtgList.Rows[0].Cells[3].Value.ToString();
string work_2 = dtgList.Rows[1].Cells[3].Value.ToString();
string work_3 = dtgList.Rows[2].Cells[3].Value.ToString();
string work_4 = dtgList.Rows[3].Cells[3].Value.ToString();
string work_5 = dtgList.Rows[4].Cells[3].Value.ToString();
string work_6 = dtgList.Rows[5].Cells[3].Value.ToString();
string work_7 = dtgList.Rows[6].Cells[3].Value.ToString();
string work_8 = dtgList.Rows[7].Cells[3].Value.ToString();
string work_9 = dtgList.Rows[8].Cells[3].Value.ToString();
string work_10 = dtgList.Rows[9].Cells[3].Value.ToString();
string work_11 = dtgList.Rows[10].Cells[3].Value.ToString();
string work_12 = dtgList.Rows[11].Cells[3].Value.ToString();
string work_13 = dtgList.Rows[12].Cells[3].Value.ToString();
string work_14 = dtgList.Rows[13].Cells[3].Value.ToString();
string work_15 = dtgList.Rows[14].Cells[3].Value.ToString();
string work_16 = dtgList.Rows[15].Cells[3].Value.ToString();
string work_17 = dtgList.Rows[16].Cells[3].Value.ToString();
string work_18 = dtgList.Rows[17].Cells[3].Value.ToString();
string work_19 = dtgList.Rows[18].Cells[3].Value.ToString();
string work_20 = dtgList.Rows[19].Cells[3].Value.ToString();
string work_21 = dtgList.Rows[20].Cells[3].Value.ToString();
string work_22 = dtgList.Rows[21].Cells[3].Value.ToString();
string work_23 = dtgList.Rows[22].Cells[3].Value.ToString();
string work_24 = dtgList.Rows[23].Cells[3].Value.ToString();
string work_25 = dtgList.Rows[24].Cells[3].Value.ToString();
string work_26 = dtgList.Rows[25].Cells[3].Value.ToString();
string work_27 = dtgList.Rows[26].Cells[3].Value.ToString();
string work_28 = dtgList.Rows[27].Cells[3].Value.ToString();
string work_29 = dtgList.Rows[28].Cells[3].Value.ToString();
string work_30 = dtgList.Rows[29].Cells[3].Value.ToString();
string work_31 = dtgList.Rows[30].Cells[3].Value.ToString();
///////////////////////////////////////////////////////////
string contract_1 = dtgList.Rows[0].Cells[4].Value.ToString();
string contract_2 = dtgList.Rows[1].Cells[4].Value.ToString();
string contract_3 = dtgList.Rows[2].Cells[4].Value.ToString();
string contract_4 = dtgList.Rows[3].Cells[4].Value.ToString();
string contract_5 = dtgList.Rows[4].Cells[4].Value.ToString();
string contract_6 = dtgList.Rows[5].Cells[4].Value.ToString();
string contract_7 = dtgList.Rows[6].Cells[4].Value.ToString();
string contract_8 = dtgList.Rows[7].Cells[4].Value.ToString();
string contract_9 = dtgList.Rows[8].Cells[4].Value.ToString();
string contract_10 = dtgList.Rows[9].Cells[4].Value.ToString();
string contract_11 = dtgList.Rows[10].Cells[4].Value.ToString();
string contract_12 = dtgList.Rows[11].Cells[4].Value.ToString();
string contract_13 = dtgList.Rows[12].Cells[4].Value.ToString();
string contract_14 = dtgList.Rows[13].Cells[4].Value.ToString();
string contract_15 = dtgList.Rows[14].Cells[4].Value.ToString();
string contract_16 = dtgList.Rows[15].Cells[4].Value.ToString();
string contract_17 = dtgList.Rows[16].Cells[4].Value.ToString();
string contract_18 = dtgList.Rows[17].Cells[4].Value.ToString();
string contract_19 = dtgList.Rows[18].Cells[4].Value.ToString();
string contract_20 = dtgList.Rows[19].Cells[4].Value.ToString();
string contract_21 = dtgList.Rows[20].Cells[4].Value.ToString();
string contract_22 = dtgList.Rows[21].Cells[4].Value.ToString();
string contract_23 = dtgList.Rows[22].Cells[4].Value.ToString();
string contract_24 = dtgList.Rows[23].Cells[4].Value.ToString();
string contract_25 = dtgList.Rows[24].Cells[4].Value.ToString();
string contract_26 = dtgList.Rows[25].Cells[4].Value.ToString();
string contract_27 = dtgList.Rows[26].Cells[4].Value.ToString();
string contract_28 = dtgList.Rows[27].Cells[4].Value.ToString();
string contract_29 = dtgList.Rows[28].Cells[4].Value.ToString();
string contract_30 = dtgList.Rows[29].Cells[4].Value.ToString();
string contract_31 = dtgList.Rows[30].Cells[4].Value.ToString();
/////////////////////////////
string p_id = txtPersonelID.Text;
//Populate with DataGridView
dtgdata.Rows.Add($"{date_1}", $"{work_1}", $"{contract_1}", $"{p_id}");
dtgdata.Rows.Add($"{date_2}", $"{work_2}", $"{contract_2}", $"{p_id}");
dtgdata.Rows.Add($"{date_3}", $"{work_3}", $"{contract_3}", $"{p_id}");
dtgdata.Rows.Add($"{date_4}", $"{work_4}", $"{contract_4}", $"{p_id}");
dtgdata.Rows.Add($"{date_5}", $"{work_5}", $"{contract_5}", $"{p_id}");
dtgdata.Rows.Add($"{date_6}", $"{work_6}", $"{contract_6}", $"{p_id}");
dtgdata.Rows.Add($"{date_7}", $"{work_7}", $"{contract_7}", $"{p_id}");
dtgdata.Rows.Add($"{date_8}", $"{work_8}", $"{contract_8}", $"{p_id}");
dtgdata.Rows.Add($"{date_9}", $"{work_9}", $"{contract_9}", $"{p_id}");
dtgdata.Rows.Add($"{date_10}", $"{work_10}", $"{contract_10}", $"{p_id}");
dtgdata.Rows.Add($"{date_11}", $"{work_11}", $"{contract_11}", $"{p_id}");
dtgdata.Rows.Add($"{date_12}", $"{work_12}", $"{contract_12}", $"{p_id}");
dtgdata.Rows.Add($"{date_13}", $"{work_13}", $"{contract_13}", $"{p_id}");
dtgdata.Rows.Add($"{date_14}", $"{work_14}", $"{contract_14}", $"{p_id}");
dtgdata.Rows.Add($"{date_15}", $"{work_15}", $"{contract_15}", $"{p_id}");
dtgdata.Rows.Add($"{date_16}", $"{work_16}", $"{contract_16}", $"{p_id}");
dtgdata.Rows.Add($"{date_17}", $"{work_17}", $"{contract_17}", $"{p_id}");
dtgdata.Rows.Add($"{date_18}", $"{work_18}", $"{contract_18}", $"{p_id}");
dtgdata.Rows.Add($"{date_19}", $"{work_19}", $"{contract_19}", $"{p_id}");
dtgdata.Rows.Add($"{date_20}", $"{work_20}", $"{contract_20}", $"{p_id}");
dtgdata.Rows.Add($"{date_21}", $"{work_21}", $"{contract_21}", $"{p_id}");
dtgdata.Rows.Add($"{date_22}", $"{work_22}", $"{contract_22}", $"{p_id}");
dtgdata.Rows.Add($"{date_23}", $"{work_23}", $"{contract_23}", $"{p_id}");
dtgdata.Rows.Add($"{date_24}", $"{work_24}", $"{contract_24}", $"{p_id}");
dtgdata.Rows.Add($"{date_25}", $"{work_25}", $"{contract_25}", $"{p_id}");
dtgdata.Rows.Add($"{date_26}", $"{work_26}", $"{contract_26}", $"{p_id}");
dtgdata.Rows.Add($"{date_27}", $"{work_27}", $"{contract_27}", $"{p_id}");
dtgdata.Rows.Add($"{date_28}", $"{work_28}", $"{contract_28}", $"{p_id}");
dtgdata.Rows.Add($"{date_29}", $"{work_29}", $"{contract_29}", $"{p_id}");
dtgdata.Rows.Add($"{date_30}", $"{work_30}", $"{contract_30}", $"{p_id}");
dtgdata.Rows.Add($"{date_31}", $"{work_31}", $"{contract_31}", $"{p_id}");
#endregion
return dtgdata;
}
#endregion
问题是;
当 DataGridView 行由于某种原因为空时;代码给出空异常。
我想做什么?
我想检查这些值是否为空,如果它们为空,则将它们转换为字符串(如“n/a”)。
我想我需要使用 foreach,但我不知道该怎么做。
如果您尝试通过访问单元格来获取 datagridview 中的数据,那您就过不去。
通常更容易告诉 DataGridView 它将显示哪种项目,并告诉每一列它应该显示的 属性 的名称。最后,您为 datagridView 提供了一个集合,其中包含它应该显示的项目。
当操作员编辑数据网格视图、添加和删除行、更改值时,您什么都不做。一旦操作员通知您他已完成编辑,例如通过单击“立即应用”或“确定”按钮,您就可以获取数据源。您可以确定它是 up-to-date,您不必自己从单元格中读取值。
class AssignedWork
{
public DateTime Date {get; set;}
public string WorkType {get; set;} // can you make this an enum?
public string Contract {get; set;}
public int PersonnelId {get; set;}
}
使用visual studio 设计器添加列。设置数据属性名称
var columnDate = new DataGridViewColumn
{
...
DataPropertyName = nameof(AssignedWork.Date),
}
var columnPersonnelId = new DataGridViewColumn
{
...
DataPropertyName = nameof(AssignedWork.PersonnelId),
}
var columnWorkType : new DataGridViewComboBoxColumn()
{
...
DataPropertyName = nameof(AssignedWork.WorkType),
}
现在获取要显示的数据,并将其放入BindingList,或者从一个空的DataGridView开始:
IList<AssignedWork> initialData = FetchInitialData();
BindingList<AssignedWork> displayedData = new BindingList<AssignedWork>(initialData);
this.dataGridView1.DataSource = displayedData;
您在列中指定了哪些列是可编辑的、列的顺序以及 属性 必须显示的格式,例如:您想如何显示日期时间?格式类似于 String.Format.
操作员可以添加/更新/删除行。删除/更新行时,您无需执行任何操作。
如果操作员添加新行,您必须用初始数据填充该行。
displayedData.AddingNew += OnAddingNewAssignedWork;
操作员添加新Row时,会调用下面的方法,可以为添加的Row指定初始内容。如果需要,您甚至可以显示一个对话框,操作员必须在其中 select 一个 PersonnelId。
void OnAddingNewAssignedWork(object sender, AddingNewEventArgs e)
{
e.NewObject = new AssignedWork
{
Date = DateTime.Today,
...
};
}
如果您不订阅该活动,将添加默认 new AssignedWork
作为新行
当操作员正在编辑单元格时,他可能想让单元格暂时处于无效格式,例如因为他想 copy-paste 单元格中的数据。是否允许无效数据由您决定。
您可以通过处理事件 CellValidating / RowValidating / Validating 来做到这一点。
CellValidating 是最简单的:您获得必须验证的单元格的索引,因此您可以获取单元格和单元格中的值。您知道该列,所以您知道其中应该包含什么:如果值不正确,请将 e.Cancel 设置为 true。
CellValidating 很容易,但不是很用户友好:操作员必须完成单元格的内容才能离开。他无法从 datagridview 中的另一行复制粘贴值。所以考虑 RowValidating 或 Validating。
如果您希望操作员在没有有效值时离开单元格/行/网格,请考虑禁用“确定”按钮,直到它具有所有有效值。您还可以为无效单元格的背景着色,以警告操作员该单元格具有无效值。
dataGridView1.RowValidating += ValidatingRow;
void ValidatingRow(object sender, DataGridViewCellCancelEventArgs e)
{
// use e.RowIndex to get the Row, and check the validity of the Cells
// color the BackGround of the Cells that contain invalid data
}
操作员完成所有编辑后,他可以点击一个按钮:
private void OnButtonOk_Clicked(object sender, ...)
{
// Get the data from the datagridview and process it.
// The updated data is already in the datasource:
this.ProcessData(this.displayedData);
// or if you forgot to remember the displayed data:
BindingList<AssignedWork> displayedData = (BindingList<AssignedWork>)this.dataGridView.DataSource;
this.ProcessData(this.displayedData);
}
void ProcessData(ICollection<AssignedWork> dataToProcess)
{
foreach (AssignedWork assignedWork in dataToProcess)
{
...
}
}
不清楚 dtgList
是什么。它似乎是 DataGridView
。我假设 dtgList
是 DataGridView
.
如果 dtgList
有一个 DataSource
,那么您应该使用那个 DataSource
而不是在网格中循环。然而,如果网格没有 DataSource
那么你显然需要遍历网格来获取数据。
使用某种“bindingsource/datasource”几乎总是更好。这将使您的事情变得容易得多。学习如何使用数据源而不是“手动”将数据输入网格。
鉴于此,我假设 DataGridView
dtgList
没有 DataSource
而您想从 DataGridView
中创建 DataTable
.显然,您可以按照发布的代码中的路线进行操作;但是,您已经知道这种方法的问题……即少于 31 天的月份或 运行 31 天之前的代码将在当前状态下失败。
正如我评论的那样,您的代码是固定的,并且仅在 31 天时有效。这个明显的限制意味着您将不得不做其他事情,当然正如您所说的那样……“我想我需要使用 foreach……”……您是对的。这里需要一个 foreach
或一个简单的 for
循环。
目前图片和代码有些混乱,因为代码(不必要地)创建了 93 个变量:31 个日期、31 个工作和 31 个合同变量。这些变量来自网格 dtgList
中的单元格。但是,当代码将行添加到 DataTable
时,它使用文本框中的 p_id
作为“id”列?图片显示 id 存在于网格中,我不知道为什么这个值是从文本框而不是网格中获取的。这令人困惑。
我假设您想使用文本框中的值。
假设 DataGridView
dtgList
没有 DataSource
,那么下面的代码应该从给定的 DataGridView
产生一个 DataTable
然后添加一个“ID”列,并用文本框中的值填充该列中的每一行。
方法是这样的……首先创建一个空的 DataTable
。接下来,开始 foreach
循环以在网格中添加“所有”列。此示例假定 ID 列不在网格中。将列添加到 table 后,将创建一个 DataRow
变量 newRow
以提供我们需要将各个网格单元格值添加到的变量。该行... newRow = dt.NewRow();
将创建一个包含适当列的新行。我们会将网格中的值添加到该行,然后将该行添加到 table.
接下来,我们启动一个 for
循环来遍历网格中的所有行。我们可以为此使用 foreach
循环,但是,如果我们使用 for
循环,我们可以在代码后面使用 for
循环索引来引用网格行。
接下来检查网格中的当前行是否是“新行”……我们要忽略这一行而不是将其添加到 table。接下来,另一个 for
循环开始循环遍历每一行中的每一列。在这个循环中,我们要检查并确保网格单元格中的 Value
不是 null
。如果出于任何原因,dgv.Rows[rowIndex].Cells[colIndex].Value
处的单元格值为 null
,当我们尝试在 null
对象上调用 ToString()
方法时,代码将抛出异常。如果值是 null
我们简单地忽略它,因为它的值显然什么都没有……即空。
最后,我们将该行中每个单元格的值添加到我们之前创建的 newRow
中。然后最后将该行添加到 DataTable
.
接下来,由于原始网格中不存在 ID 列,我们需要添加 ID 列,然后遍历 table 中的所有行并将值添加到中的每一行ID 列。然后最后 return DataTable
private DataTable GetDTFromGrid(DataGridView dgv, string p_id) {
DataTable dt = new DataTable();
foreach (DataGridViewColumn column in dgv.Columns) {
dt.Columns.Add(column.Name);
}
DataRow newRow;
for (int rowIndex = 0; rowIndex < dgv.Rows.Count; rowIndex++) {
if (!dgv.Rows[rowIndex].IsNewRow) {
newRow = dt.NewRow();
for (int colIndex = 0; colIndex < dgv.Columns.Count; colIndex++) {
if (dgv.Rows[rowIndex].Cells[colIndex].Value != null) {
newRow[colIndex] = dgv.Rows[rowIndex].Cells[colIndex].Value.ToString();
}
}
dt.Rows.Add(newRow);
}
}
// remove this code if p_id is already in dgv
dt.Columns.Add(new DataColumn("ID"));
foreach (DataRow row in dt.Rows) {
row["ID"] = p_id;
}
return dt;
}
为了测试和完成答案,下面是一个完整的例子。加载时,表单会用一些数据填充网格(在左侧)。请注意,网格没有数据源。添加了一个按钮来调用上面的方法。然后returned DataTable
作为DataSource
到第二个格子(右边)。
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
FillGrid(dataGridView1);
}
private void FillGrid(DataGridView dgv) {
AddColToDGV(dgv, "Date");
AddColToDGV(dgv, "Type");
AddColToDGV(dgv, "Contract");
//AddColToDGV(dgv, "ID");
DateTime date = DateTime.Now;
for (int i = 0; i < 10; i++) {
date = date.Subtract(new TimeSpan(24, 0, 0));
dgv.Rows.Add(date, "Type_" + i, "Contact" + i);
}
}
private void AddColToDGV(DataGridView dgv, string name) {
DataGridViewTextBoxColumn col = new DataGridViewTextBoxColumn();
col.Name = name;
dgv.Columns.Add(col);
}
private void button1_Click(object sender, EventArgs e) {
DataTable dt = GetDTFromGrid(dataGridView1, txtPersonelID.Text);
dataGridView2.DataSource = dt;
}
终极菜鸟的问候。
我正在使用 C# 在 WinForms 中为我的地质学家团队准备时间 sheet 计划程序,但在从 DataGridView 值填充 PDF 表时遇到问题。
我的计划中有一个每月的时间表。当您单击 Get Excel(我将其更改为 PDF)时,程序会根据 DataGridView 值创建一个 pdf 文件。如果您有 31 天的完整数据网格视图,则没有问题。但是当这个月有30天或者用户想在月底之前获取PDF时,它会给出空异常。
代码在这里。
#region Functions
DataTable MakeDataTable()
{
//Create time sheet table object
DataTable dtgdata = new DataTable();
//Define columns
dtgdata.Columns.Add("Date");
dtgdata.Columns.Add("Type of Work");
dtgdata.Columns.Add("Contract");
dtgdata.Columns.Add("Personnel ID");
#region PopulateData
string date_1 = dtgList.Rows[0].Cells[1].Value.ToString();
string date_2 = dtgList.Rows[1].Cells[1].Value.ToString();
string date_3 = dtgList.Rows[2].Cells[1].Value.ToString();
string date_4 = dtgList.Rows[3].Cells[1].Value.ToString();
string date_5 = dtgList.Rows[4].Cells[1].Value.ToString();
string date_6 = dtgList.Rows[5].Cells[1].Value.ToString();
string date_7 = dtgList.Rows[6].Cells[1].Value.ToString();
string date_8 = dtgList.Rows[7].Cells[1].Value.ToString();
string date_9 = dtgList.Rows[8].Cells[1].Value.ToString();
string date_10 = dtgList.Rows[9].Cells[1].Value.ToString();
string date_11 = dtgList.Rows[10].Cells[1].Value.ToString();
string date_12 = dtgList.Rows[11].Cells[1].Value.ToString();
string date_13 = dtgList.Rows[12].Cells[1].Value.ToString();
string date_14 = dtgList.Rows[13].Cells[1].Value.ToString();
string date_15 = dtgList.Rows[14].Cells[1].Value.ToString();
string date_16 = dtgList.Rows[15].Cells[1].Value.ToString();
string date_17 = dtgList.Rows[16].Cells[1].Value.ToString();
string date_18 = dtgList.Rows[17].Cells[1].Value.ToString();
string date_19 = dtgList.Rows[18].Cells[1].Value.ToString();
string date_20 = dtgList.Rows[19].Cells[1].Value.ToString();
string date_21 = dtgList.Rows[20].Cells[1].Value.ToString();
string date_22 = dtgList.Rows[21].Cells[1].Value.ToString();
string date_23 = dtgList.Rows[22].Cells[1].Value.ToString();
string date_24 = dtgList.Rows[23].Cells[1].Value.ToString();
string date_25 = dtgList.Rows[24].Cells[1].Value.ToString();
string date_26 = dtgList.Rows[25].Cells[1].Value.ToString();
string date_27 = dtgList.Rows[26].Cells[1].Value.ToString();
string date_28 = dtgList.Rows[27].Cells[1].Value.ToString();
string date_29 = dtgList.Rows[28].Cells[1].Value.ToString();
string date_30 = dtgList.Rows[29].Cells[1].Value.ToString();
string date_31 = dtgList.Rows[30].Cells[1].Value.ToString();
////////////////////////////////////////////////////////////
string work_1 = dtgList.Rows[0].Cells[3].Value.ToString();
string work_2 = dtgList.Rows[1].Cells[3].Value.ToString();
string work_3 = dtgList.Rows[2].Cells[3].Value.ToString();
string work_4 = dtgList.Rows[3].Cells[3].Value.ToString();
string work_5 = dtgList.Rows[4].Cells[3].Value.ToString();
string work_6 = dtgList.Rows[5].Cells[3].Value.ToString();
string work_7 = dtgList.Rows[6].Cells[3].Value.ToString();
string work_8 = dtgList.Rows[7].Cells[3].Value.ToString();
string work_9 = dtgList.Rows[8].Cells[3].Value.ToString();
string work_10 = dtgList.Rows[9].Cells[3].Value.ToString();
string work_11 = dtgList.Rows[10].Cells[3].Value.ToString();
string work_12 = dtgList.Rows[11].Cells[3].Value.ToString();
string work_13 = dtgList.Rows[12].Cells[3].Value.ToString();
string work_14 = dtgList.Rows[13].Cells[3].Value.ToString();
string work_15 = dtgList.Rows[14].Cells[3].Value.ToString();
string work_16 = dtgList.Rows[15].Cells[3].Value.ToString();
string work_17 = dtgList.Rows[16].Cells[3].Value.ToString();
string work_18 = dtgList.Rows[17].Cells[3].Value.ToString();
string work_19 = dtgList.Rows[18].Cells[3].Value.ToString();
string work_20 = dtgList.Rows[19].Cells[3].Value.ToString();
string work_21 = dtgList.Rows[20].Cells[3].Value.ToString();
string work_22 = dtgList.Rows[21].Cells[3].Value.ToString();
string work_23 = dtgList.Rows[22].Cells[3].Value.ToString();
string work_24 = dtgList.Rows[23].Cells[3].Value.ToString();
string work_25 = dtgList.Rows[24].Cells[3].Value.ToString();
string work_26 = dtgList.Rows[25].Cells[3].Value.ToString();
string work_27 = dtgList.Rows[26].Cells[3].Value.ToString();
string work_28 = dtgList.Rows[27].Cells[3].Value.ToString();
string work_29 = dtgList.Rows[28].Cells[3].Value.ToString();
string work_30 = dtgList.Rows[29].Cells[3].Value.ToString();
string work_31 = dtgList.Rows[30].Cells[3].Value.ToString();
///////////////////////////////////////////////////////////
string contract_1 = dtgList.Rows[0].Cells[4].Value.ToString();
string contract_2 = dtgList.Rows[1].Cells[4].Value.ToString();
string contract_3 = dtgList.Rows[2].Cells[4].Value.ToString();
string contract_4 = dtgList.Rows[3].Cells[4].Value.ToString();
string contract_5 = dtgList.Rows[4].Cells[4].Value.ToString();
string contract_6 = dtgList.Rows[5].Cells[4].Value.ToString();
string contract_7 = dtgList.Rows[6].Cells[4].Value.ToString();
string contract_8 = dtgList.Rows[7].Cells[4].Value.ToString();
string contract_9 = dtgList.Rows[8].Cells[4].Value.ToString();
string contract_10 = dtgList.Rows[9].Cells[4].Value.ToString();
string contract_11 = dtgList.Rows[10].Cells[4].Value.ToString();
string contract_12 = dtgList.Rows[11].Cells[4].Value.ToString();
string contract_13 = dtgList.Rows[12].Cells[4].Value.ToString();
string contract_14 = dtgList.Rows[13].Cells[4].Value.ToString();
string contract_15 = dtgList.Rows[14].Cells[4].Value.ToString();
string contract_16 = dtgList.Rows[15].Cells[4].Value.ToString();
string contract_17 = dtgList.Rows[16].Cells[4].Value.ToString();
string contract_18 = dtgList.Rows[17].Cells[4].Value.ToString();
string contract_19 = dtgList.Rows[18].Cells[4].Value.ToString();
string contract_20 = dtgList.Rows[19].Cells[4].Value.ToString();
string contract_21 = dtgList.Rows[20].Cells[4].Value.ToString();
string contract_22 = dtgList.Rows[21].Cells[4].Value.ToString();
string contract_23 = dtgList.Rows[22].Cells[4].Value.ToString();
string contract_24 = dtgList.Rows[23].Cells[4].Value.ToString();
string contract_25 = dtgList.Rows[24].Cells[4].Value.ToString();
string contract_26 = dtgList.Rows[25].Cells[4].Value.ToString();
string contract_27 = dtgList.Rows[26].Cells[4].Value.ToString();
string contract_28 = dtgList.Rows[27].Cells[4].Value.ToString();
string contract_29 = dtgList.Rows[28].Cells[4].Value.ToString();
string contract_30 = dtgList.Rows[29].Cells[4].Value.ToString();
string contract_31 = dtgList.Rows[30].Cells[4].Value.ToString();
/////////////////////////////
string p_id = txtPersonelID.Text;
//Populate with DataGridView
dtgdata.Rows.Add($"{date_1}", $"{work_1}", $"{contract_1}", $"{p_id}");
dtgdata.Rows.Add($"{date_2}", $"{work_2}", $"{contract_2}", $"{p_id}");
dtgdata.Rows.Add($"{date_3}", $"{work_3}", $"{contract_3}", $"{p_id}");
dtgdata.Rows.Add($"{date_4}", $"{work_4}", $"{contract_4}", $"{p_id}");
dtgdata.Rows.Add($"{date_5}", $"{work_5}", $"{contract_5}", $"{p_id}");
dtgdata.Rows.Add($"{date_6}", $"{work_6}", $"{contract_6}", $"{p_id}");
dtgdata.Rows.Add($"{date_7}", $"{work_7}", $"{contract_7}", $"{p_id}");
dtgdata.Rows.Add($"{date_8}", $"{work_8}", $"{contract_8}", $"{p_id}");
dtgdata.Rows.Add($"{date_9}", $"{work_9}", $"{contract_9}", $"{p_id}");
dtgdata.Rows.Add($"{date_10}", $"{work_10}", $"{contract_10}", $"{p_id}");
dtgdata.Rows.Add($"{date_11}", $"{work_11}", $"{contract_11}", $"{p_id}");
dtgdata.Rows.Add($"{date_12}", $"{work_12}", $"{contract_12}", $"{p_id}");
dtgdata.Rows.Add($"{date_13}", $"{work_13}", $"{contract_13}", $"{p_id}");
dtgdata.Rows.Add($"{date_14}", $"{work_14}", $"{contract_14}", $"{p_id}");
dtgdata.Rows.Add($"{date_15}", $"{work_15}", $"{contract_15}", $"{p_id}");
dtgdata.Rows.Add($"{date_16}", $"{work_16}", $"{contract_16}", $"{p_id}");
dtgdata.Rows.Add($"{date_17}", $"{work_17}", $"{contract_17}", $"{p_id}");
dtgdata.Rows.Add($"{date_18}", $"{work_18}", $"{contract_18}", $"{p_id}");
dtgdata.Rows.Add($"{date_19}", $"{work_19}", $"{contract_19}", $"{p_id}");
dtgdata.Rows.Add($"{date_20}", $"{work_20}", $"{contract_20}", $"{p_id}");
dtgdata.Rows.Add($"{date_21}", $"{work_21}", $"{contract_21}", $"{p_id}");
dtgdata.Rows.Add($"{date_22}", $"{work_22}", $"{contract_22}", $"{p_id}");
dtgdata.Rows.Add($"{date_23}", $"{work_23}", $"{contract_23}", $"{p_id}");
dtgdata.Rows.Add($"{date_24}", $"{work_24}", $"{contract_24}", $"{p_id}");
dtgdata.Rows.Add($"{date_25}", $"{work_25}", $"{contract_25}", $"{p_id}");
dtgdata.Rows.Add($"{date_26}", $"{work_26}", $"{contract_26}", $"{p_id}");
dtgdata.Rows.Add($"{date_27}", $"{work_27}", $"{contract_27}", $"{p_id}");
dtgdata.Rows.Add($"{date_28}", $"{work_28}", $"{contract_28}", $"{p_id}");
dtgdata.Rows.Add($"{date_29}", $"{work_29}", $"{contract_29}", $"{p_id}");
dtgdata.Rows.Add($"{date_30}", $"{work_30}", $"{contract_30}", $"{p_id}");
dtgdata.Rows.Add($"{date_31}", $"{work_31}", $"{contract_31}", $"{p_id}");
#endregion
return dtgdata;
}
#endregion
问题是;
当 DataGridView 行由于某种原因为空时;代码给出空异常。
我想做什么?
我想检查这些值是否为空,如果它们为空,则将它们转换为字符串(如“n/a”)。
我想我需要使用 foreach,但我不知道该怎么做。
如果您尝试通过访问单元格来获取 datagridview 中的数据,那您就过不去。
通常更容易告诉 DataGridView 它将显示哪种项目,并告诉每一列它应该显示的 属性 的名称。最后,您为 datagridView 提供了一个集合,其中包含它应该显示的项目。
当操作员编辑数据网格视图、添加和删除行、更改值时,您什么都不做。一旦操作员通知您他已完成编辑,例如通过单击“立即应用”或“确定”按钮,您就可以获取数据源。您可以确定它是 up-to-date,您不必自己从单元格中读取值。
class AssignedWork
{
public DateTime Date {get; set;}
public string WorkType {get; set;} // can you make this an enum?
public string Contract {get; set;}
public int PersonnelId {get; set;}
}
使用visual studio 设计器添加列。设置数据属性名称
var columnDate = new DataGridViewColumn
{
...
DataPropertyName = nameof(AssignedWork.Date),
}
var columnPersonnelId = new DataGridViewColumn
{
...
DataPropertyName = nameof(AssignedWork.PersonnelId),
}
var columnWorkType : new DataGridViewComboBoxColumn()
{
...
DataPropertyName = nameof(AssignedWork.WorkType),
}
现在获取要显示的数据,并将其放入BindingList,或者从一个空的DataGridView开始:
IList<AssignedWork> initialData = FetchInitialData();
BindingList<AssignedWork> displayedData = new BindingList<AssignedWork>(initialData);
this.dataGridView1.DataSource = displayedData;
您在列中指定了哪些列是可编辑的、列的顺序以及 属性 必须显示的格式,例如:您想如何显示日期时间?格式类似于 String.Format.
操作员可以添加/更新/删除行。删除/更新行时,您无需执行任何操作。
如果操作员添加新行,您必须用初始数据填充该行。
displayedData.AddingNew += OnAddingNewAssignedWork;
操作员添加新Row时,会调用下面的方法,可以为添加的Row指定初始内容。如果需要,您甚至可以显示一个对话框,操作员必须在其中 select 一个 PersonnelId。
void OnAddingNewAssignedWork(object sender, AddingNewEventArgs e)
{
e.NewObject = new AssignedWork
{
Date = DateTime.Today,
...
};
}
如果您不订阅该活动,将添加默认 new AssignedWork
作为新行
当操作员正在编辑单元格时,他可能想让单元格暂时处于无效格式,例如因为他想 copy-paste 单元格中的数据。是否允许无效数据由您决定。 您可以通过处理事件 CellValidating / RowValidating / Validating 来做到这一点。
CellValidating 是最简单的:您获得必须验证的单元格的索引,因此您可以获取单元格和单元格中的值。您知道该列,所以您知道其中应该包含什么:如果值不正确,请将 e.Cancel 设置为 true。
CellValidating 很容易,但不是很用户友好:操作员必须完成单元格的内容才能离开。他无法从 datagridview 中的另一行复制粘贴值。所以考虑 RowValidating 或 Validating。
如果您希望操作员在没有有效值时离开单元格/行/网格,请考虑禁用“确定”按钮,直到它具有所有有效值。您还可以为无效单元格的背景着色,以警告操作员该单元格具有无效值。
dataGridView1.RowValidating += ValidatingRow;
void ValidatingRow(object sender, DataGridViewCellCancelEventArgs e)
{
// use e.RowIndex to get the Row, and check the validity of the Cells
// color the BackGround of the Cells that contain invalid data
}
操作员完成所有编辑后,他可以点击一个按钮:
private void OnButtonOk_Clicked(object sender, ...)
{
// Get the data from the datagridview and process it.
// The updated data is already in the datasource:
this.ProcessData(this.displayedData);
// or if you forgot to remember the displayed data:
BindingList<AssignedWork> displayedData = (BindingList<AssignedWork>)this.dataGridView.DataSource;
this.ProcessData(this.displayedData);
}
void ProcessData(ICollection<AssignedWork> dataToProcess)
{
foreach (AssignedWork assignedWork in dataToProcess)
{
...
}
}
不清楚 dtgList
是什么。它似乎是 DataGridView
。我假设 dtgList
是 DataGridView
.
如果 dtgList
有一个 DataSource
,那么您应该使用那个 DataSource
而不是在网格中循环。然而,如果网格没有 DataSource
那么你显然需要遍历网格来获取数据。
使用某种“bindingsource/datasource”几乎总是更好。这将使您的事情变得容易得多。学习如何使用数据源而不是“手动”将数据输入网格。
鉴于此,我假设 DataGridView
dtgList
没有 DataSource
而您想从 DataGridView
中创建 DataTable
.显然,您可以按照发布的代码中的路线进行操作;但是,您已经知道这种方法的问题……即少于 31 天的月份或 运行 31 天之前的代码将在当前状态下失败。
正如我评论的那样,您的代码是固定的,并且仅在 31 天时有效。这个明显的限制意味着您将不得不做其他事情,当然正如您所说的那样……“我想我需要使用 foreach……”……您是对的。这里需要一个 foreach
或一个简单的 for
循环。
目前图片和代码有些混乱,因为代码(不必要地)创建了 93 个变量:31 个日期、31 个工作和 31 个合同变量。这些变量来自网格 dtgList
中的单元格。但是,当代码将行添加到 DataTable
时,它使用文本框中的 p_id
作为“id”列?图片显示 id 存在于网格中,我不知道为什么这个值是从文本框而不是网格中获取的。这令人困惑。
我假设您想使用文本框中的值。
假设 DataGridView
dtgList
没有 DataSource
,那么下面的代码应该从给定的 DataGridView
产生一个 DataTable
然后添加一个“ID”列,并用文本框中的值填充该列中的每一行。
方法是这样的……首先创建一个空的 DataTable
。接下来,开始 foreach
循环以在网格中添加“所有”列。此示例假定 ID 列不在网格中。将列添加到 table 后,将创建一个 DataRow
变量 newRow
以提供我们需要将各个网格单元格值添加到的变量。该行... newRow = dt.NewRow();
将创建一个包含适当列的新行。我们会将网格中的值添加到该行,然后将该行添加到 table.
接下来,我们启动一个 for
循环来遍历网格中的所有行。我们可以为此使用 foreach
循环,但是,如果我们使用 for
循环,我们可以在代码后面使用 for
循环索引来引用网格行。
接下来检查网格中的当前行是否是“新行”……我们要忽略这一行而不是将其添加到 table。接下来,另一个 for
循环开始循环遍历每一行中的每一列。在这个循环中,我们要检查并确保网格单元格中的 Value
不是 null
。如果出于任何原因,dgv.Rows[rowIndex].Cells[colIndex].Value
处的单元格值为 null
,当我们尝试在 null
对象上调用 ToString()
方法时,代码将抛出异常。如果值是 null
我们简单地忽略它,因为它的值显然什么都没有……即空。
最后,我们将该行中每个单元格的值添加到我们之前创建的 newRow
中。然后最后将该行添加到 DataTable
.
接下来,由于原始网格中不存在 ID 列,我们需要添加 ID 列,然后遍历 table 中的所有行并将值添加到中的每一行ID 列。然后最后 return DataTable
private DataTable GetDTFromGrid(DataGridView dgv, string p_id) {
DataTable dt = new DataTable();
foreach (DataGridViewColumn column in dgv.Columns) {
dt.Columns.Add(column.Name);
}
DataRow newRow;
for (int rowIndex = 0; rowIndex < dgv.Rows.Count; rowIndex++) {
if (!dgv.Rows[rowIndex].IsNewRow) {
newRow = dt.NewRow();
for (int colIndex = 0; colIndex < dgv.Columns.Count; colIndex++) {
if (dgv.Rows[rowIndex].Cells[colIndex].Value != null) {
newRow[colIndex] = dgv.Rows[rowIndex].Cells[colIndex].Value.ToString();
}
}
dt.Rows.Add(newRow);
}
}
// remove this code if p_id is already in dgv
dt.Columns.Add(new DataColumn("ID"));
foreach (DataRow row in dt.Rows) {
row["ID"] = p_id;
}
return dt;
}
为了测试和完成答案,下面是一个完整的例子。加载时,表单会用一些数据填充网格(在左侧)。请注意,网格没有数据源。添加了一个按钮来调用上面的方法。然后returned DataTable
作为DataSource
到第二个格子(右边)。
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
FillGrid(dataGridView1);
}
private void FillGrid(DataGridView dgv) {
AddColToDGV(dgv, "Date");
AddColToDGV(dgv, "Type");
AddColToDGV(dgv, "Contract");
//AddColToDGV(dgv, "ID");
DateTime date = DateTime.Now;
for (int i = 0; i < 10; i++) {
date = date.Subtract(new TimeSpan(24, 0, 0));
dgv.Rows.Add(date, "Type_" + i, "Contact" + i);
}
}
private void AddColToDGV(DataGridView dgv, string name) {
DataGridViewTextBoxColumn col = new DataGridViewTextBoxColumn();
col.Name = name;
dgv.Columns.Add(col);
}
private void button1_Click(object sender, EventArgs e) {
DataTable dt = GetDTFromGrid(dataGridView1, txtPersonelID.Text);
dataGridView2.DataSource = dt;
}