DataGridViewComboBoxColumn:日期格式不适用于列表中的项目

DataGridViewComboBoxColumn: Date format doesn't apply to items in list

我目前正在开发一个带有 DataGridView 的 C# 应用程序,并试图显示一个 DataGridViewComboBoxColumn,其中包含 DateTime 对象作为 ValueType 和 ValueMember。

我已经使用列的 DefaultCellStyle.Format 方法应用了格式设置,但这似乎只适用于选定的值,而不适用于列表中的所有项目。

因此,当我选择某些内容时,它显示正常,但是当打开下拉菜单时,其中的所有项目都显示为 DateTime 对象的标准字符串表示形式。

这是有意为之的行为还是我遗漏了什么?

谢谢,

托拜厄斯·廷佩

我猜网格的数据源是 DataTable 并且显然组合框列的类型是 DateTime. 如果是这种情况,那么我相信你所描述的是因为网格单元格“值”是一个实际的 DateTime 对象,网格将使用 DateTime 对象的默认 ToString() 方法维护单元格值……即……MM/DD/YYYY.

正如您所说,您可以格式化显示,但是当下拉列表可见时,这不适用于组合框中的 drop-down 项。我猜测上面可能是它以这种方式显示的原因。如果您尝试以任何其他方式对其进行格式化……网格的可怕 DataError 很可能会出现。

一个可能的解决方案……

由于组合框将包含 DateTime 个对象,并且您有获取 DateTime 个对象的方法,因此我建议您将日期放入 DataTable 结构中以下。这将是组合框的 DataSource

private DataTable GetComboTable() {
  DataTable dt = new DataTable();
  dt.Columns.Add("DateTime", typeof(DateTime));
  dt.Columns.Add("StringDateTime", typeof(string));
  return dt;
}

第一列 (DateTime) 将包含“实际”DateTime 对象,它将成为组合框的 ValueMember。这就是将映射到网格 table 中的 DateTime 列并避免 DataError.

下一个 (StringDateTime) 列将包含要在下拉列表中显示的“格式化”日期字符串。此字符串将是组合框 DisplayMember.

下面是用一些随机日期填充此 table 的示例。

private DataTable GetComboDates() {
  DataTable dt = GetComboTable();
  Random rand = new Random();
  int duration = 5 * 365;          
  DateTime randomDate = DateTime.Today.AddDays(-rand.Next(duration));
  for (int i = 0; i < 10; i++) {
    dt.Rows.Add(randomDate, String.Format("{0:yyyy/MM/dd - hh:mm:ss tt}", randomDate));
    randomDate = DateTime.Today.AddDays(-rand.Next(duration));
  }
  return dt;
}

请注意,此处格式化日期字符串适用于显示 drop-down 时用户将看到的内容。正如我们已经知道的,如果组合列 DefaultCellStyle.Format(适用于未选中组合框时用户看到的内容)与此格式不匹配,那么它们将不同。这意味着列显示格式必须与此处设置的格式匹配才能获得您描述的所需行为。

现在我们已经为组合框列创建了一个好的 DataSource,下面的函数将使用它来 return 一个用于网格的 DataGridViewComboBoxColumn

private DataGridViewComboBoxColumn GetComboColumn() {
  DataGridViewComboBoxColumn comboCol = new DataGridViewComboBoxColumn();
  comboCol.DataPropertyName = "Dates";
  comboCol.HeaderText = "Dates";
  comboCol.DisplayMember = "StringDateTime";
  comboCol.ValueMember = "DateTime";
  comboCol.Width = 175;
  DataTable comboData = GetComboDates();
  comboCol.DataSource = comboData;
  return comboCol;
}

注意:DataPropertyName 是网格中列的名称 DataTableDisplayMember 是格式化日期字符串的组合数据 table 中列的名称; ValueMember 是实际日期的组合数据 table 中列的名称。

下面是一个测试这个的例子,我相信它会在不显示下拉菜单时保持相同的下拉菜单格式。只要两种格式相同,这就应该有效。

DataTable GridTable;

public Form1() {
  InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e) {
  GridTable = GetTable();
  FillTable(GridTable);
  dataGridView1.Columns.Add(GetComboColumn());
  dataGridView1.DataSource = GridTable;
}

private DataTable GetTable() {
  DataTable dt = new DataTable();
  dt.Columns.Add("Col0", typeof(string));
  dt.Columns.Add("Dates", typeof(DateTime));
  return dt;
}

private DataGridViewComboBoxColumn GetComboColumn() {
  DataGridViewComboBoxColumn comboCol = new DataGridViewComboBoxColumn();
  comboCol.DataPropertyName = "Dates";
  comboCol.HeaderText = "Dates";
  comboCol.DisplayMember = "StringDateTime";
  comboCol.ValueMember = "DateTime";
  comboCol.Width = 175;
  DataTable comboData = GetComboDates();
  comboCol.DataSource = comboData;
  return comboCol;
}

private void FillTable(DataTable dt) {
  for (int i = 0; i < 10; i++) {
    dt.Rows.Add("C0R" + i);
  }
}

private DataTable GetComboTable() {
  DataTable dt = new DataTable();
  dt.Columns.Add("DateTime", typeof(DateTime));
  dt.Columns.Add("StringDateTime", typeof(string));
  return dt;
}

private DataTable GetComboDates() {
  DataTable dt = GetComboTable();
  Random rand = new Random();
  int duration = 5 * 365;          
  DateTime randomDate = DateTime.Today.AddDays(-rand.Next(duration));
  for (int i = 0; i < 10; i++) {
    dt.Rows.Add(randomDate, String.Format("{0:yyyy/MM/dd - hh:mm:ss tt}", randomDate));
    randomDate = DateTime.Today.AddDays(-rand.Next(duration));
  }
  return dt;
}

希望这对您有所帮助并且有意义。