您确定everyliste[i]
不为null,并且每个liste[i] 的每个开始时间和每个结束时间都不为null。?如果这些值中的任何一个为空,您想显示什么?
唉,你忘了告诉我们 的返回值db.Find(...)
,但我很确定要么liste[i]
等于 null,要么属性heureDebut
etheureFin
可以为空Datetime
如果您已定义单元格以便可以显示可为空的日期时间,请考虑更改您的代码:
var itemToDisplay = liste[i];
if (itemToDisplay != null)
{
dataGridViewListerDV.Rows.Add(itemToDisplay.date,
itemToDisplay.heureDebut, itemToDisplay.heureFin, null, null);
}
else
{
// decide what to do if item equals null
}
此外,如果 HeureDebut / HeureFine 可能为空,请考虑更改您的 DataGridViewColumns,以便它们可以显示可为空的 DateTime 而不是 DateTime。
有改进的余地
初次使用 DataGridViews 的用户倾向于直接修改 DataGridView 中的行和单元格。通过这样做,您将数据(您的模型)与该数据的显示方式(您的视图)交织在一起。
很长一段时间以来,有一种趋势将这两者分开。如果您将模型与视图分开,您可以轻松更改视图,而无需更改模型,例如,如果您想在图表中而不是表格中显示数据,或者如果您想保存XML 文件中的数据,而不是表中的数据,您的模型不必更改。同样,如果您不需要表单来显示模型,则对模型进行单元测试要容易得多。
将模型与视图分开的第三个原因是,它使您可以自由更改 DataGridView 而无需更改模型:您可以添加/删除列,更改 DateTimes 的显示方式,显示不同的颜色负值:无需更改模型即可完成所有这些更改。
为了让你的模型和视图分开,你需要一个适配器类来将你的模型转换成你希望它显示的方式。这个适配器通常被称为 ViewModel。
如果您将在几年内使用 WPF 而不是 Forms,您将看到模型和视图之间的这种分离几乎是强制的,通过使用不同的语言来描述视图 (XAML)。
但 Forms 也支持这种分离。
首先,您需要定义将在一行中显示的类。像这样的东西:
class WorkingHours
{
public DateTime Date {get; set;}
public TimeSpan? StartTime {get; set;}
public TimeSpan? EndTime {get; set;}
}
这样,可以确定 StartTime 和 EndTime 在同一天。如果您有夜班,请考虑:
class WorkingHours
{
public DateTime? StartTime {get; set;}
public DateTime? EndTime {get; set;}
}
但是你会遇到问题:如果你没有 StartTime,要显示什么日期。在展示你的模型之前,让你的模型直截了当,这样你的属性就可以很好地定义:哪些值始终可用,哪些值可以为空,它们是否会超出范围?
使用 Visual Studio Designer,您可能已经定义了列。您的列有一个属性DataPropertyName,它告诉您要显示的内容:
columnDate.DataPropertyName = nameof(WorkingHours.Date);
columnStartTime.DataPropertyName = nameof(WorkingHours.StartTime);
columnFinishTime.DataPropertyName = nameof(WorkingHours.EndTime);
如果您的 StartTime 和 EndTime 可能为空,请考虑添加如何显示空值:红色背景?或者只有一个'-',也许什么都不显示?
请参阅:因为您将模型和视图分开,所以更改视图不会影响您的模型!
我们需要一种方法来获取您的数据。这是您在问题中的方法:
private IEnumerable<WorkingHours> GetWorkingHours(...)
{
using (var dbConnection = new ConnectedDb(...))
{
... // Create DbCommand, ExecuteQuery and use DbReader to fill WorkingHours
}
}
注意:如果将来您决定更改获取数据的方式(例如使用实体框架或 Dapper,或者从 XML 文件中读取工作时间),这是唯一会改变的地方?或者更改数据库布局:再次:模型更改不会影响您的视图。
现在我们能够获取显示的数据,Displaying 是一个语句:
this.dataGridView1.DataSource = GetWorkingHours(...).ToList();
瞧!所有获取的数据都会立即显示。
但是,这只是显示。不监控更改。如果您想了解更改:添加/删除/更改行,数据应该在实现 IBindingList 的对象中,例如BindingList<T>
为此,我们需要一行代码:
private BindlingList<WorkingHours> DisplayedWorkingHours
{
get => (BindingList<WorkingHours>)this.dataGridView1.DataSource;
set => this.dataGridView1.DataSource = value;
}
所以要显示你的数据:
void InitDisplayedData()
{
this.DisplayedWorkingHours = new BindingList<WorkingHours>(this.GetWorkingHours().ToList());
}
现在,操作员所做的每一项更改都会在 bindingList 中自动更新。您不必阅读行或单元格,只需等待操作员指示他完成了数据编辑,例如通过单击按钮:
private void OnButtonOk_Clicked(object sender, ...)
{
IReadOnlyCollection<WorkingHours> editedWorkingHours = this.DisplayedWorkingHours;
// Detect which items are added / removed / changed and process the changes:
this.ProcessEditedWorkingHours(editedWorkingHours);
}
再说一遍:你看到了吗,因为我将实际数据处理与数据显示方式分开,所有模型功能都可以在没有表单的情况下进行测试。如果你改变了数据的显示方式,你的模型不必改变,如果你改变了模型,显示也不必改变。
如果您需要处理选定的行,请考虑为此添加功能:
private WorkingHours CurrentWorkingHours =>
(WorkingHours)this.dataGridView1.CurrentRow?.DataBoundItem;
private IEnumerable<WorkingHours> SelectedWorkingHours =>
this.dataGridView1.SelectedRows.Cast<DataGridViewRow>()
.Select(row => row.DataBoundItem)
.Cast<WorkingHours>();
}
结论
通过将模型与视图分离,可以更轻松地更改视图或模型,而无需更改另一个。在没有视图的情况下对模型进行单元测试更容易,如果出现问题,您可以在没有真实数据库的情况下调试视图。
Model 和 View 之间的 ViewModel 适配器通常由几个单行方法组成。
简单的来吧您好!