views:

136

answers:

2

Our DataGrid-heavy application likes to throw exceptions when double-clicking the space between rows used for resizing. The exception is The " DataGridColumnStyle cannot be used because it is not associated with a Property or a Column in the DataSource.

Most of our DataGrid-based forms inherit from one form called GridForm. Our DataSource is a DataView. I can set a breakpoint in our double-click event handler, but it's never reached. The except is caught at the Show/ShowDialog call of the entire form hosting the control. We are now running .NET 3.5, but most of this functionality was built in .NET 1.1. We had the same problem back then as well.

StackOverflow's very own Joel Coehoorn seems to have run into the same problem here: http://discuss.fogcreek.com/dotnetquestions/default.asp?cmd=show&ixPost=5780

This is a bug we've had lurking around for a good 3-4 years, so solving this would be amazing.


Here's the full exception: The DataGridColumnStyle it's complaining about differs between each grid in our application. I'm guessing this means that we have a column style that displays a column that isn't in the bound data set. The columns included in a data set will change depending on the needs for a given form, so we really do need to define some styles for columns that could or could not be there.

System.InvalidOperationException: DataGridColumnStyle of 'Real-Time Bill' cannot be used because it is not associated with a Property or Column in the DataSource.
   at System.Windows.Forms.DataGridColumnStyle.CheckValidDataSource(CurrencyManager value)
   at System.Windows.Forms.DataGridColumnStyle.GetColumnValueAtRow(CurrencyManager source, Int32 rowNum)
   at System.Windows.Forms.DataGridBoolColumn.GetColumnValueAtRow(CurrencyManager lm, Int32 row)
   at System.Windows.Forms.DataGrid.RowAutoResize(Int32 row)
   at System.Windows.Forms.DataGrid.OnMouseDown(MouseEventArgs e)
   at System.Windows.Forms.Control.WmMouseDown(Message& m, MouseButtons button, Int32 clicks)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
   at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
   at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.Run(Form mainForm)
   at CLS.Presentation.MainForm.Main(String[] args) in C:\Users\stuartb.CLS\Documents\Projects\Genesis\CLS.Presentation\MainForm.cs:line 2712


As requested, here's the definition for the column in question. Granted, it's not always this column that the exception indicates. As noted in my previous edit, column styles that look for a column that is not in the bound DataTable cause this problem. In this example, ConsumptionBill is not in the bound DataTable. The behavior in this case is simply to have the column not be shown, and apparently crash and burn on row border double-clicks.

this.dataGridBoolColumnClientsConsumptionBill.Alignment = System.Windows.Forms.HorizontalAlignment.Center;
this.dataGridBoolColumnClientsConsumptionBill.AllowNull = false;
this.dataGridBoolColumnClientsConsumptionBill.HeaderText = "Real-Time Bill";
this.dataGridBoolColumnClientsConsumptionBill.MappingName = "ConsumptionBill";
this.dataGridBoolColumnClientsConsumptionBill.Width = 75;
+1  A: 

It's not time to think about how to handle the exception. Not until we know what the exception is.

Please post the full exception. Post the results of ex.ToString();

John Saunders
Added more information about the exception. I figured this would be something fairly common that I was simply ignorant about. Maybe not!
Stuart Branham
This does not look familiar. I used to use the DataGrid extensively, binding it to a DataSet as a cheap form of navigation UI. I never saw this. OTOH, it looks like it's complaining that column is unbound. Is that true? How is that column defined? Please show the code that configures it. It looks like it's trying to resize the row based on the data in the row, but this column has no data. Also, please say which version of .NET it's running today.
John Saunders
Added even more information. The column is in fact not in the DataTable in this case. I figured that much would be breaking this. However, we need to be able to have this kind of flexibility, so simply taking out column styles that might not always isn't an option.
Stuart Branham
I'd suggest that column style should perhaps be added dynamically, and not stay in the grid when there's nothing to refer to.
John Saunders
Thanks for the guidance, John. I was able to solve the problem by dynamically *removing* column styles. I figured that would be a lot more maintable than dynamically adding them.
Stuart Branham
+2  A: 

Thanks to a little guided digging, with help from John, I was able to resolve the issue generally with the following method.

IList<DataGridColumnStyle> missingColumnStyles = new List<DataGridColumnStyle>();
/// <summary>
/// Adjust the grid's definition to accept the given DataTable.
/// </summary>
/// <param name="table"></param>
protected virtual void AdjustGridForData(DataTable table, DataGrid grid)
{
    // Remove column styles whose mapped columns are missing.
    // This fixes the notorious, uncatchable exception caused when double-clicking row borders.
    var columnStyles = grid.TableStyles[table.TableName].GridColumnStyles;

    // Add previously removed column styles back to the grid, in case the new bound table
    // has something we removed last time this method was executed.
    foreach (var missingColumnStyle in missingColumnStyles)
        columnStyles.Add(missingColumnStyle);
    missingColumnStyles.Clear();

    // Move the offending column styles into a separate list.
    var missingColumns = new List<string>();
    foreach (DataGridColumnStyle style in columnStyles)
    {
        if (!table.Columns.Contains(style.MappingName))
            missingColumns.Add(style.MappingName);
    }
    foreach (var column in missingColumns)
    {
        missingColumnStyles.Add(columnStyles[column]);
        columnStyles.Remove(columnStyles[column]);
    }
}
Stuart Branham