C#Winforms DataGridView时间列

如何在DataGridView中显示Time-picker列?

我不需要选择日期。 我只需要时间选择。

实际上,有一种比创建自定义DataGridView列更好的方法。 我目前为我的应用程序做的是当我输入DataGridView的TIMESTAMP列时,我将DateTimePicker控件直接放在单元格上。 当用户单击单元格(从而确认其选择)时,DateTimePicker Visible设置为False,DateTimePicker的值将放入单元格。 默认情况下,DateTimePicker控件可见性设置为False,直到我需要它。 我还将此用于常规单元格上的ComboBox控件,用户无法输入自定义值,并且必须使用“设置”屏幕中的项目列表。 这种技术非常适合伪装。 我没有现成的代码,但代码更少,更容易维护恕我直言。

以上和以下技术取自在Win Forms 2.0中的DataGridView控件中伪造替代控件

编辑:这是代码 –

private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e) { if (selectAllToolStripMenuItem.Checked) selectAllToolStripMenuItem.Checked = false; if (dtPicker.Visible) dtPicker.Visible = false; if (e.ColumnIndex >= 0) { if (dataGridView1.Columns[e.ColumnIndex].Name == "Delete") { if (adminIsLoggedIn) { removeRow(e); } else { MessageBox.Show("You must be logged in as an Administrator in order to change the facility configuration.", "Delete Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } else if (dataGridView1.Columns[e.ColumnIndex].Name == "TIMESTAMP") { if (adminIsLoggedIn) { setNewCellDate(e); } } ..... } // --- 

}

 private void setNewCellDate(DataGridViewCellEventArgs e) { dtPicker.Size = dataGridView1.CurrentCell.Size; dtPicker.Top = dataGridView1.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, true).Top + dataGridView1.Top; dtPicker.Left = dataGridView1.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, true).Left + dataGridView1.Left; if (!(object.Equals(Convert.ToString(dataGridView1.CurrentCell.Value), ""))) dtPicker.Value = Convert.ToDateTime(dataGridView1.CurrentCell.Value); dtPicker.Visible = true; } 

为了寻找同样的事情,我终于找到了一篇MSDN文章,该文章展示了如何创建自定义CalendarColumn,因此我使用了该代码示例并对其进行了修改以创建TimeColumn。 它工作得很好 – 非常干净,基于Microsoft Code示例。 不是黑客,可以有效和可靠地数据绑定。

要实现,只需将这些类添加到项目中,然后在DataGridView的ColumnType字段中选择TimeColumn。

 public class TimeColumn : DataGridViewColumn { public TimeColumn() : base(new TimeCell()) { } public override DataGridViewCell CellTemplate { get { return base.CellTemplate; } set { // Ensure that the cell used for the template is a CalendarCell. if (value != null && !value.GetType().IsAssignableFrom(typeof(TimeCell))) { throw new InvalidCastException("Must be a TimeCell"); } base.CellTemplate = value; } } } public class TimeCell : DataGridViewTextBoxCell { public TimeCell() : base() { // Use the short date format. this.Style.Format = "t"; } public override void InitializeEditingControl(int rowIndex, object initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle) { // Set the value of the editing control to the current cell value. base.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle); TimeEditingControl ctl = DataGridView.EditingControl as TimeEditingControl; // Use the default row value when Value property is null. if (this.Value == null) { ctl.Value = (DateTime)this.DefaultNewRowValue; } else { ctl.Value = (DateTime)this.Value; } } public override Type EditType { get { // Return the type of the editing control that CalendarCell uses. return typeof(TimeEditingControl); } } public override Type ValueType { get { // Return the type of the value that CalendarCell contains. return typeof(DateTime); } } public override object DefaultNewRowValue { get { // Use the current date and time as the default value. return DateTime.Now; } } } class TimeEditingControl : DateTimePicker, IDataGridViewEditingControl { DataGridView dataGridView; private bool valueChanged = false; int rowIndex; public TimeEditingControl() { this.Format = DateTimePickerFormat.Time; this.ShowUpDown = true; // replace the timepicker calendar drop down with a up down scroller } // Implements the IDataGridViewEditingControl.EditingControlFormattedValue // property. public object EditingControlFormattedValue { get { return this.Value.ToShortTimeString(); } set { if (value is String) { try { // This will throw an exception of the string is // null, empty, or not in the format of a date. this.Value = DateTime.Parse((String)value); } catch { // In the case of an exception, just use the // default value so we're not left with a null // value. this.Value = DateTime.Now; } } } } // Implements the // IDataGridViewEditingControl.GetEditingControlFormattedValue method. public object GetEditingControlFormattedValue( DataGridViewDataErrorContexts context) { return EditingControlFormattedValue; } // Implements the // IDataGridViewEditingControl.ApplyCellStyleToEditingControl method. public void ApplyCellStyleToEditingControl( DataGridViewCellStyle dataGridViewCellStyle) { this.Font = dataGridViewCellStyle.Font; this.CalendarForeColor = dataGridViewCellStyle.ForeColor; this.CalendarMonthBackground = dataGridViewCellStyle.BackColor; } // Implements the IDataGridViewEditingControl.EditingControlRowIndex // property. public int EditingControlRowIndex { get { return rowIndex; } set { rowIndex = value; } } // Implements the IDataGridViewEditingControl.EditingControlWantsInputKey // method. public bool EditingControlWantsInputKey( Keys key, bool dataGridViewWantsInputKey) { // Let the DateTimePicker handle the keys listed. switch (key & Keys.KeyCode) { case Keys.Left: case Keys.Up: case Keys.Down: case Keys.Right: case Keys.Home: case Keys.End: case Keys.PageDown: case Keys.PageUp: return true; default: return !dataGridViewWantsInputKey; } } // Implements the IDataGridViewEditingControl.PrepareEditingControlForEdit // method. public void PrepareEditingControlForEdit(bool selectAll) { // No preparation needs to be done. } // Implements the IDataGridViewEditingControl // .RepositionEditingControlOnValueChange property. public bool RepositionEditingControlOnValueChange { get { return false; } } // Implements the IDataGridViewEditingControl // .EditingControlDataGridView property. public DataGridView EditingControlDataGridView { get { return dataGridView; } set { dataGridView = value; } } // Implements the IDataGridViewEditingControl // .EditingControlValueChanged property. public bool EditingControlValueChanged { get { return valueChanged; } set { valueChanged = value; } } // Implements the IDataGridViewEditingControl // .EditingPanelCursor property. public Cursor EditingPanelCursor { get { return base.Cursor; } } protected override void OnValueChanged(EventArgs eventargs) { // Notify the DataGridView that the contents of the cell // have changed. valueChanged = true; this.EditingControlDataGridView.NotifyCurrentCellDirty(true); base.OnValueChanged(eventargs); } } 

AFAIK,有一个直接的方法来做到这一点。 我认为唯一的方法是创建一个Custom DataGridview列。 选中此链接以创建自定义datagridview列

很抱歉回复旧post,但这是我能找到的唯一一个有人调整MS代码的地方。 为了回应RThomas,我已经做到了这一点但是我发现在绑定到数据表时使用TimeColumn存在问题。 我将它用于员工时间表输入,因此日期元素不可见,只是时间。 当我输入数据时它工作正常,但是当我尝试编辑数据时出错了。

OnValueChanged事件中的单元格值是正确的(使用Debug我可以看到Me.Value的值),但在DataGridView.CellEndEditing或CellValidated事件中,该值显示当前日期和编辑的时间值。 奇怪的是,如果用户移动到另一个单元格,然后返回到TimeCell,然后再次移动到另一个单元格,则该值是正确的,但在初始编辑之后,日期是错误的。

我查看了所有不同的事件,但它似乎是在DataGridView中编辑的值和提交到绑定到DataGridView的Datatable之间的事情。