Datagridview - Change yyyymmdd to mm/dd/yyyy

R

rob

I have a class that among others exposes a string property "Date". The
date in this property is stored in the form yyyymmdd. Now I do the
following

1) Generate a DataGridViewTextBoxColumn column for that property
2) Add the column to the datagridview
3) Populate a BindingSource by adding all instances of the above
mentioned class.
4) Assign the BindingSource to the datagridview's DataSource property

At this point the column with the date shows the date in the form
yyyymmdd. I now try to change that by reading the cell's value, convert
it to mm/dd/yyyy and set the new cell value. Unfortunately, this has no
effect at all. Even in debug mode when I change the value manually in
the watch window it refuses the new value without any exception.

I guess the first question is if it is possible at all to change the
value of a cell without(!) propegating that change back to the data
source. If it is possible how is it done? If it is not possible then
how can I achive my goal?

Thanks
 
J

john smith

rob said:
I have a class that among others exposes a string property "Date". The
date in this property is stored in the form yyyymmdd. Now I do the
following

1) Generate a DataGridViewTextBoxColumn column for that property
2) Add the column to the datagridview
3) Populate a BindingSource by adding all instances of the above
mentioned class.
4) Assign the BindingSource to the datagridview's DataSource property

At this point the column with the date shows the date in the form
yyyymmdd. I now try to change that by reading the cell's value, convert
it to mm/dd/yyyy and set the new cell value. Unfortunately, this has no
effect at all. Even in debug mode when I change the value manually in
the watch window it refuses the new value without any exception.

I guess the first question is if it is possible at all to change the
value of a cell without(!) propegating that change back to the data
source. If it is possible how is it done? If it is not possible then
how can I achive my goal?

Thanks

Have you tried to set the DataFormatString to {0:MM/dd/yyyy} ? (Not that
this specific date format makes any sense to me - I'd take the original
ISO Date format over that any day...)
 
B

Bart Mermuys

Hi,

rob said:
I have a class that among others exposes a string property "Date". The
date in this property is stored in the form yyyymmdd. Now I do the
following

1) Generate a DataGridViewTextBoxColumn column for that property
2) Add the column to the datagridview
3) Populate a BindingSource by adding all instances of the above
mentioned class.
4) Assign the BindingSource to the datagridview's DataSource property

At this point the column with the date shows the date in the form
yyyymmdd. I now try to change that by reading the cell's value, convert
it to mm/dd/yyyy and set the new cell value. Unfortunately, this has no
effect at all. Even in debug mode when I change the value manually in
the watch window it refuses the new value without any exception.

You can use the DataGridView's CellParsing and CellFormating events:

using System.Globalization;

private void dataGridView_CellFormatting(object sender,
DataGridViewCellFormattingEventArgs e)
{
if (dataGridView.Columns[e.ColumnIndex].DataPropertyName == "Date" )
{
DateTime dt = DateTime.ParseExact((string)e.Value, "yyyymmdd",
DateTimeFormatInfo.InvariantInfo);

e.Value = dt.ToString("mm/dd/yyyy",
DateTimeFormatInfo.InvariantInfo); //*

e.FormattingApplied = true;
}
}

private void dataGridView_CellParsing(object sender,
DataGridViewCellParsingEventArgs e)
{
if (dataGridView.Columns[e.ColumnIndex].DataPropertyName == "Date")
{
DateTime dt = DateTime.ParseExact((string)e.Value, "mm/dd/yyyy",
DateTimeFormatInfo.InvariantInfo); //*

e.Value = dt.ToString("yyyymmdd",
DateTimeFormatInfo.InvariantInfo);

e.ParsingApplied = true;
}
}

(*) you could also use "d" and DateTimeFormatInfo.CurrentInfo to show the
date in the short-date-format for the users current culture.

HTH,
Greetings
 
G

Greg Burns

DataFormatString sounds like a property of the DataGrid from ASP.NET, not
WinForm's DataGridView.

Use code like so:

Dim colShipDate As New DataGridViewTextBoxColumn()

colShipDate.SortMode = DataGridViewColumnSortMode.Automatic
colShipDate.AutoSizeMode = DataGridViewAutoSizeColumnMode.ColumnHeader
colShipDate.DataPropertyName = "ShipDate"
colShipDate.HeaderText = "Ship Date"
colShipDate.Name = "ShipDate"
colShipDate.ReadOnly = True

Dim cellStyle As DataGridViewCellStyle = New DataGridViewCellStyle()
cellStyle.BackColor = Color.Thistle
cellStyle.Format = "MM/dd/yyyy"

colShipDate.DefaultCellStyle = cellStyle

DataGridView1.Columns.Add(colShipDate)

Greg
 
R

rob

Great, it works now. There are two problems left, though:

1) The glyph is not shown anymore on any of the colums when I set the
datasource property of my datagridview to the bindingsource. This works
fine when I create rows on my datagridview and manually set each cell's
content.

2) This approach is much slower (factor 1.5) then by setting the
content of each cell manually. Is there a way to improve this?

Thanks,
 
J

john smith

Greg said:
DataFormatString sounds like a property of the DataGrid from ASP.NET, not
WinForm's DataGridView.

Yes it is. Somehow my brain only seems to have registered 3 words of
what he said: GridView, Date and Format (I was very tired). The solution
works, but indeed just in ASP.Net...
 
B

Bart Mermuys

Hi,

rob said:
Great, it works now. There are two problems left, though:

1) The glyph is not shown anymore on any of the colums when I set the
datasource property of my datagridview to the bindingsource. This works
fine when I create rows on my datagridview and manually set each cell's
content.

If you mean the sorting glyph, then that's because the list the
BindingSource is using doesn't support sorting. In case you didn't assign a
list to the BindingSource.DataSource then the default list is a
BindingList<T> which doesn't support sorting.

You could use a SortableBindingList<T> posted at the end of this message.
Create a Data Source (Menu-Data) for your class (eg. Customer), then from
the Data Sources window drag it on the Form. Then from code in form_load
assign the actual list to be used, example:

private void Form_Load(...)
{
someBindingSource.DataSource = new SortableBindingList<Customer>();
someBindingSource.Add( new Customer("fkdsf") );
someBindingSource.Add( new Customer("fdsf") );
}

But sorting the 'Date' column correctly while being a string would be hard
and require more code, so if it is possible use a DateTime for your Date
column.
2) This approach is much slower (factor 1.5) then by setting the
content of each cell manually. Is there a way to improve this?

Not sure about this, probely some databinding overhead, gonna have a look
later, but i doubt i'll find something.

HTH,
Greetings

The code for SortableBindingList<T> is at
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnforms/html/winforms02182005.asp ,
but because some parts are missing, i pasted the complete code here:

using System;
using System.Reflection;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;

namespace test1.CellFormat
{
public class SortableBindingList<T> : BindingList<T>
{
private PropertyDescriptor sortProp = null;
private ListSortDirection sortDir =
ListSortDirection.Ascending;

private bool isSorted = false;

protected override bool SupportsSortingCore
{
get { return true; }
}

protected override void ApplySortCore(PropertyDescriptor property,
ListSortDirection direction)
{
PropertyComparer<T> pc =
new PropertyComparer<T>(property, direction);

((List<T>)this.Items).Sort(pc);

isSorted = true;
sortProp = property;
sortDir = direction;

// Let bound controls know they should refresh their views
this.OnListChanged(new
ListChangedEventArgs(ListChangedType.Reset, -1));
}

protected override bool IsSortedCore
{
get { return isSorted; }
}

protected override void RemoveSortCore()
{
// can't unsort
}

protected override PropertyDescriptor SortPropertyCore
{
get { return sortProp; }
}

protected override ListSortDirection SortDirectionCore
{
get { return sortDir; }
}
}

public class PropertyComparer<T> : System.Collections.Generic.IComparer<T>
{
// The following code contains code implemented by Rockford Lhotka:
//
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnadvnet/html/vbnet01272004.asp

private PropertyDescriptor _property;
private ListSortDirection _direction;

public PropertyComparer(PropertyDescriptor property, ListSortDirection
direction)
{
_property = property;
_direction = direction;
}

#region IComparer<T>

public int Compare(T xWord, T yWord)
{
// Get property values
object xValue = GetPropertyValue(xWord, _property.Name);
object yValue = GetPropertyValue(yWord, _property.Name);

// Determine sort order
if (_direction == ListSortDirection.Ascending)
{
return CompareAscending(xValue, yValue);
}
else
{
return CompareDescending(xValue, yValue);
}
}

public bool Equals(T xWord, T yWord)
{
return xWord.Equals(yWord);
}

public int GetHashCode(T obj)
{
return obj.GetHashCode();
}

#endregion

// Compare two property values of any type
private int CompareAscending(object xValue, object yValue)
{
int result;

// If values implement IComparer
if (xValue is IComparable)
{
result = ((IComparable)xValue).CompareTo(yValue);
}
// If values don't implement IComparer but are equivalent
else if (xValue.Equals(yValue))
{
result = 0;
}
// Values don't implement IComparer and are not equivalent, so compare
as string values
else result = xValue.ToString().CompareTo(yValue.ToString());

// Return result
return result;
}

private int CompareDescending(object xValue, object yValue)
{
// Return result adjusted for ascending or descending sort order ie
// multiplied by 1 for ascending or -1 for descending
return CompareAscending(xValue, yValue) * -1;
}

private object GetPropertyValue(T value, string property)
{
// Get property
PropertyInfo propertyInfo = value.GetType().GetProperty(property);

// Return value
return propertyInfo.GetValue(value, null);
}
}
}
 
C

Cor Ligthert [MVP]

Rob,

It is easy to do, however you have to be wise.

Make from the String property a DateTime value.

With that is everything done by Microsoft what you ask.

(And for that is not a small amount of code that they made).

Cor
 
B

Bart Mermuys

Hi,

Cor Ligthert said:
Rob,

It is easy to do, however you have to be wise.

Make from the String property a DateTime value.

With that is everything done by Microsoft what you ask.

Not if he wants to use databinding, when you have custom objects then
sorting is not supported by default (even if the property is DateTime)
because the default list used for binding is BindingList<T> which does not
support sorting. That's why he needs SortableBindingList<T>.

Greetings
 
R

rob

Cor,

Do you mean I should change the property of the class that exposes the
date which is used for the data binding? If so the problem is that I
can't change this because other components already expect the format we
currently have. If not then can you please elaborate?

Thanks
 
C

Cor Ligthert [MVP]

Rob,

Using string for a DateTime is for me from the time from the punchcard. In
the Microsoft Database server all datetimes are in ticks (diferent methods
for short Time and DateTime). As well is a DateTime in Net the datetime in
ticks (other format). Which means that in can be represented in any way you
want and even standard based on your culture settings. The different formats
are almost seamless converted.

For from from String to Date is
DateTime.parse
Convert.DateTiem
CDate

For from Date to String is the overloaded ToString with the IFormatProvider

For bounding with non complex datacontrols are the binding events

http://www.vb-tips.com/default.aspx?ID=c4832a2a-2b95-4ded-93d9-4deb7fa4a0b8

And there is even much more by instance the way to interact with the
database server

http://www.vb-tips.com/default.aspx?ID=886bba68-8a2f-4b99-8f66-7139b8970071

So if there is so much done by Microsoft to help you to do it correct, what
is it than not to use it?

I hope that this gives an idea

Cor
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top