angus_young_acdc
asked on
MonthCalendar and DataGridView - Very Slow Loading.
I have a DataGridView with several columns. If a user selects a cell in the date column a monthCalendar control appears at that location.
My issue is that it is extremely slow (it appears fast, but attempting to select a date seems to take a long time). I have used the exact same code (posted below) for a textBox click event and it works perfectly fast. Does anybody know what may be wrong?
My issue is that it is extremely slow (it appears fast, but attempting to select a date seems to take a long time). I have used the exact same code (posted below) for a textBox click event and it works perfectly fast. Does anybody know what may be wrong?
if (dataGridView.CurrentRow.Cells["transactionDate"].Selected)
{
monthCalendar.Visible = true;
monthCalendar.Top = 40;
monthCalendar.Left = 50;
monthCalendar.BringToFront();
monthCalendar.Capture = true;
while (monthCalendar.Visible == true)
{
Application.DoEvents();
}
dataGridView.CurrentRow.Cells["transactionDate"].Value = _accountDate;
return;
}
private void monthCalendar_MouseUp(object sender, MouseEventArgs e)
{
switch (monthCalendar.HitTest(e.Location).HitArea)
{
case MonthCalendar.HitArea.Date:
monthCalendar.Visible = false;
break;
case MonthCalendar.HitArea.NextMonthDate:
break;
case MonthCalendar.HitArea.PrevMonthDate:
break;
}
_accountDate = monthCalendar.SelectionStart.ToShortDateString();
}
ASKER
In the example provided it is adding the CalendarColumn to the grid as a new column. How can I assign the custom class to a column that already exists? Or how can I actually use this? I currently have lots of code for the other columns and seems like a re-write would be required.
Well, presuming that your columns are autogenerated when binding to a datatable, you can just add the following code:
It uses the same header text and dataproperty as the original column that contains a date, inserts itself in the same position, and then hides the original.
As for your code, I'm guessing it's to do with the while loop. Why not remove the loop, and set the column's date after you hide the Calendar control:
dataGridView.CurrentRow.Ce lls["trans actionDate "].Value = monthCalendar.SelectionSta rt;
Why are you converting the date selected by the user to a string, is the Date column not DateTime?
You're only testing for one hittest type, so why use switch?
It uses the same header text and dataproperty as the original column that contains a date, inserts itself in the same position, and then hides the original.
As for your code, I'm guessing it's to do with the while loop. Why not remove the loop, and set the column's date after you hide the Calendar control:
dataGridView.CurrentRow.Ce
Why are you converting the date selected by the user to a string, is the Date column not DateTime?
You're only testing for one hittest type, so why use switch?
// Using Calendar column
DataGridViewColumn autoGenDateCol = dataGridView1.Columns["Date Column"];
CalendarColumn calendarCol = new CalendarColumn ();
calendarCol.HeaderText = autoGenDateCol.HeaderText;
calendarCol.DataPropertyName = autoGenDateCol.DataPropertyName;
calendarCol.Name = "Date Column2";
dataGridView1.Columns.Insert(autoGenDateCol.Index, calendarCol);
autoGenDateCol.Visible = false;
// Your modified code
if (dataGridView.CurrentRow.Cells["transactionDate"].Selected)
{
monthCalendar.Visible = true;
monthCalendar.Top = 40;
monthCalendar.Left = 50;
monthCalendar.BringToFront();
monthCalendar.Capture = true;
dataGridView.Enabled = false;
return;
}
private void monthCalendar_MouseUp(object sender, MouseEventArgs e)
{
if (monthCalendar.HitTest(e.Location).HitArea == MonthCalendar.HitArea.Date){
dataGridView.CurrentRow.Cells["transactionDate"].Value = monthCalendar.SelectionStart;
monthCalendar.Visible = false;
dataGridView.Enabled = true;
}
}
ASKER
Hi oobayly
Unfortunately not, they have been created just via Edit Columns as there is no real binding, it's taking a value from XML to populate the table.
Good idea about hiding after populating the date, shall try that out now.
I'm converting the date to a string as that's just the way it is read/written to the XML, so just seemed easier (albeit uglier) rather than just converting it later.
As for the switch... I'm not sure, should I just change it to an if statement for the HitArea.Date?
Unfortunately not, they have been created just via Edit Columns as there is no real binding, it's taking a value from XML to populate the table.
Good idea about hiding after populating the date, shall try that out now.
I'm converting the date to a string as that's just the way it is read/written to the XML, so just seemed easier (albeit uglier) rather than just converting it later.
As for the switch... I'm not sure, should I just change it to an if statement for the HitArea.Date?
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Hi again,
I have tried that code but unfortunately I can't seem to get it working correctly. I'm either getting a null reference exception or an invalid cast exception.
They all happen here:
public override void InitializeEditingControl(i nt rowIndex, object
initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle)
{
// Set the value of the editing control to the current cell value.
base.InitializeEditingCont rol(rowInd ex, initialFormattedValue,
dataGridViewCellStyle);
CalendarEditingControl ctl =
DataGridView.EditingContro l as CalendarEditingControl;
ctl.Value = (DateTime)this.Value; // Exception thrown
}
I have tried that code but unfortunately I can't seem to get it working correctly. I'm either getting a null reference exception or an invalid cast exception.
They all happen here:
public override void InitializeEditingControl(i
initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle)
{
// Set the value of the editing control to the current cell value.
base.InitializeEditingCont
dataGridViewCellStyle);
CalendarEditingControl ctl =
DataGridView.EditingContro
ctl.Value = (DateTime)this.Value; // Exception thrown
}
ASKER
Got it working by removing code and doing a bit of a hack. Also it is a lot faster (most likely due to your suggestion about the loop). Thanks a lot1
This MSDN article explains how to do it. Once you understand how it works, it's simple to create a whole host (no pun intended) of custom columns. So far I've got a DateTimePicker column, a NumericUpDown column and a column that allows editing of binary data by displaying it as a hex string.
http://msdn.microsoft.com/en-us/library/7tas5c80.aspxhttp://msdn.microsoft.com/en-us/library/7tas5c80.aspx