3

I want to display a TimeSpan field in a DataGridView column as hhmm. And allow the user to edit it in this format. As far as I understand, I need to add some logic to CellFormatting, CellParsing, and CellValidating events. So I guess I must check the column name, and handle it for those that require this.

But how else can I better solve this for the purpose of code reuse? Can I make a custom DataGridViewColumn class where I can put this logic? How would that be achieved? I can't see any events existing for the DataGridViewColumn class, so not really sure what to do here.

bretddog
  • 5,411
  • 11
  • 63
  • 111

2 Answers2

1

I would look at DataGridViewColumn.CellTemplate property, which is of this type:

public abstract class DataGridViewCell : DataGridViewElement, ICloneable, IDisposable

which has these interesting properties:

Value: object
ValueType: Type
ValueTypeConverter: TypeConverter

from there, I would look at the TypeConverter class.

Hope this helps, that's what I could gather in about 2 minutes of looking through ILSpy.

scrat.squirrel
  • 3,607
  • 26
  • 31
0

Maybe it is too late for you, but I guess it would help others. I had almost the same issue yesterday. I solved it by creating class-wrapper to my TimeSpan member, where I overrode ToString method (in order to display time in preferred format) and created Parse(String) method, which is called automatically when user is finishing cell editing. Finally, in order to catch exceptions, which may be generated in Parse method, create handler for DataGridView's DataError event. Example:

class TimeSpanDecorator
{
    protected TimeSpan timeSpan;
    public TimeSpanDecorator(TimeSpan ts)
    {
        timeSpan = ts;
    }
    public override string ToString() // return required TimeSpan view
    {
        return timeSpan.Hours + ":" + timeSpan.Minutes;
    }
    public static TimeSpanDecorator Parse(String value) // parse entered value in any way you want
    {
        String[] parts = value.Split(':');
        if (parts.Length != 2)
            throw new ArgumentException("Wrong format");
        int hours = Int32.Parse(parts[0]);
        int minutes = Int32.Parse(parts[1]);
        TimeSpanDecorator result = new TimeSpanDecorator(new TimeSpan(hours, minutes, 0));
        if (result.timeSpan.Ticks < 0)
            throw new ArgumentException("You should provide positive time value");
        return result;
    }
    //other members
}

internal partial class MainForm : Form
{
    (...)
    private void dataGridView_DataError(object sender, DataGridViewDataErrorEventArgs e)
    {
        MessageBox.Show("Error occured: " + e.Exception.Message, "Warning!"); // showing generated argument exception
        e.ThrowException = false; // telling form that we have processed the error
    }
}

Hope this will help anyone.

Eadel
  • 3,797
  • 6
  • 38
  • 43