3

如何在 DataGridView 中显示时间选择器列?

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

4

4 回答 4

3

在寻找同样的东西时,我终于找到了一篇MSDN 文章,其中展示了如何制作自定义 CalendarColumn,因此我使用了该代码示例并对其进行了修改以创建 TimeColumn。它工作得很好 - 非常干净并且基于 Microsoft 代码示例。不是 hack,可以高效可靠地进行数据绑定。

要实现,只需将这些类添加到您的项目中,然后在 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);
    }
}
于 2011-12-07T20:04:44.040 回答
1

实际上,有比创建自定义 DataGridView 列更好的方法。我目前为我的应用程序所做的是,当输入 DataGridView 的 TIMESTAMP 列时,我将 DateTimePicker 控件直接放置在单元格上。当用户单击单元格外(从而确认他的选择)时,DateTimePicker Visible 设置为 False,并且 DateTimePicker 的值被放入单元格中。默认情况下,DateTimePicker 控件 Visibility 设置为 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;
}
于 2009-11-29T02:31:33.150 回答
0

AFAIK,有一种直接的方法可以做到这一点。我认为唯一的方法是创建一个自定义 DataGridview 列。检查此链接以创建自定义 datagridview 列

于 2009-11-27T09:27:19.930 回答
0

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

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

I've looked at all different events but it seems to be something between the value being edited in the DataGridView and committed to the Datatable bound to the DataGridView.

于 2013-08-02T10:51:48.137 回答