Domanda

Come mostrare una colonna Time-picker in DataGridView?

Non ho bisogno di scegliere Data. Ho solo bisogno di tempo per essere selezionato.

È stato utile?

Soluzione

In realtà, c'è un modo migliore della creazione di una colonna DataGridView personalizzata. Quello che faccio attualmente per la mia applicazione è quando viene inserita la colonna TIMESTAMP di DataGridView, posiziono un controllo DateTimePicker direttamente sulla cella. Quando l'utente ha fatto clic fuori dalla cella (confermando così la sua selezione), DateTimePicker Visible è impostato su False e il valore di DateTimePicker viene inserito nella cella. Per impostazione predefinita, il controllo DateTimePicker Visibilità è impostato su False fino a quando non ne ho bisogno. Lo uso anche per i controlli ComboBox su celle normali in cui l'utente non può immettere un valore personalizzato e deve utilizzare l'elenco di elementi dalla schermata di installazione. Questa tecnica è ottima per simularla. Non ho il codice prontamente disponibile, ma è meno codice e più facile da mantenere IMHO.

La tecnica precedente e seguente è stata presa da Falsi controlli alternativi all'interno di un controllo DataGridView in Win Forms 2.0

Modifica: ecco il codice -

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;
}

Altri suggerimenti

Alla ricerca di questa stessa cosa ho finalmente trovato un Articolo MSDN che mostra come creare un CalendarColumn personalizzato , quindi ho usato questo esempio di codice e l'ho modificato per creare un TimeColumn. Funziona benissimo, molto pulito e basato sull'esempio di codice Microsoft. Non è un hack e può essere integrato in modo efficiente e affidabile.

Per implementare è sufficiente aggiungere queste classi al progetto e quindi selezionare TimeColumn nel campo ColumnType di DataGridView.

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, c'è un modo diretto per farlo. Penso che l'unico modo sia quello di creare una colonna DataGridview personalizzata. Controlla questo link per creando una colonna personalizzata di datagridview

Ci scusiamo per la risposta a un vecchio thread, ma questo è l'unico posto che ho trovato dove qualcuno ha adattato il codice MS come me. In risposta a RThomas, l'ho fatto ma sto riscontrando problemi con l'utilizzo di TimeColumn quando associato a un datatable. Lo sto usando per l'inserimento della scheda attività dei dipendenti, quindi l'elemento data non è visibile, solo l'ora. Quando inserisco i dati funziona correttamente, ma quando provo a modificarli qualcosa va storto.

Il valore della cella è corretto nell'evento OnValueChanged (utilizzando Debug posso vedere il valore di Me.Value) ma negli eventi DataGridView.CellEndEditing o CellValidated il valore mostra la data corrente e il valore dell'ora modificato. Stranamente, se l'utente si sposta in un'altra cella, quindi di nuovo in TimeCell, quindi in un'altra cella il valore è corretto, ma dopo la modifica iniziale la data è errata.

Ho esaminato tutti i diversi eventi, ma sembra che ci sia qualcosa tra il valore in fase di modifica in DataGridView e il commit sul Datatable associato a DataGridView.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top