This is a migrated thread and some comments may be shown as answers.

Auto-generating custom columns causing column to appear multiple times

3 Answers 360 Views
GridView
This is a migrated thread and some comments may be shown as answers.
Fred
Top achievements
Rank 1
Fred asked on 17 Mar 2011, 02:46 PM

I have a RadGridView:

<Telerik:RadGridView Name="recordGrid"  ItemsSource="{Binding RecordList,Mode=TwoWay}" SelectedItem="{Binding CurrentRecord,Mode=TwoWay}" ShowGroupPanel="False" AutoGenerateColumns="True" AutoGeneratingColumn="RadGridView_AutoGeneratingColumn">
</Telerik:RadGridView>

As you can see, the grid is bound to a DataTable object called RecordList and the SelectedItem is bound to a DataRow object called CurrentRecord. The RecordList DataTable is generated dynamically and can have any combination of user-defined columns and rows. Because I don't know the columns ahead of time, I use AutoGenerateColumns to take care of that.

The first column will always be an ID column that identifies the row and is hidden from the user by canceling the AutoGenerateColumn event whenever the column header is "ID". The rest of the columns are user defined. 

Up to there, it all works. The problem comes when I need to create a custom column type to be auto-generated. Some columns, as defined by the user, need to display other UI controls such as buttons in the cell. To do this, I've created a RecordColumn class that extends Telerik.Windows.Controls.GridViewColumn. It is defined as follows:

public class RecordColumn : Telerik.Windows.Controls.GridViewColumn
   {
       public override FrameworkElement CreateCellElement(GridViewCell cell, object dataItem)
       {
           StackPanel cellData = new StackPanel();
           return cellData;
       }
   }

Nothing fancy at the moment. Just trying to get it working so all it does is return an empty StackPanel to go in the cell when it's created. 

Now, here's my AutoGeneratingColumns event code, which I use to instantiate the RecordColumn.

private void RadGridView_AutoGeneratingColumn(object sender, GridViewAutoGeneratingColumnEventArgs e)
{
    String headerText = e.Column.Header.ToString();
    if (headerText == "ID")
    {
        e.Cancel = true;
    }
    else
    {
        if (!(e.Column is RecordColumn))
        {
            RecordColumn rc = new RecordColumn(); 
            rc.Header = headerText;
            e.Column = rc;
        }
    }
}

The first time the RadGridView is loaded, everything looks fine. The user-defined columns are displayed as expected. If I do anything that causes the RecordList DataTable binding to update (such as adding or deleting a row), the AutoGeneratingColumns event fires again and doubles the columns. I can keep doing this, causing the columns to double every time. 

I can trace the AutoGeneratingColumns event being fired each time and it always (except for the "ID" column) goes into the code that creates a new RecordColumn. I'm guessing that's where it's creating the extra columns each time. Looking through the e.Column object though, I don't see anything that tells me I don't need to generate this column again. Each time the column type is RadGridViewColumn even if I've previously changed them all to RecordColumn, so that doesn't work. 

I have verified that my DataTable on the back-end only contains one set of the columns. This is purely on the UI side. 

If I don't use the custom column, everything works fine and when I update the binding the columns don't duplicate. 

3 Answers, 1 is accepted

Sort by
0
Fred
Top achievements
Rank 1
answered on 17 Mar 2011, 05:19 PM

I created a clean solution to make sure I could reproduce the issue outside of my MVVM project and I can. 

I think the problem has something to do with how I'm refreshing the DataTable. Whenever I add or delete a row from the back-end DataTable, I recreate the whole data table and then update the bound object to point to the new data table. 

For example, here's my UpdateRecordList method that does just this:

private void UpdateRecordList()
  {
      //This function represents pulling the data from the database into a temp DataTable 
      //and then setting the RecordList to the new DataTable
 
      DataTable temp = new DataTable();
      temp.Columns.Add("Name");
      foreach (Employee emp in emps)
      {
          DataRow dr = temp.NewRow();
          dr["Name"] = emp.Name;
          temp.Rows.Add(dr);
      }
        
      RecordList = temp;
  }
RecordList is a DataTable that the RadGridView's ItemsSource is bound to. 

The "emps" object is just a List of Employee objects that's taking place of my database object here. 

Works fine for non-custom columns. Once I add in custom columns, it starts duplicating my columns every time my UpdateRecordList function is called. 

0
Fred
Top achievements
Rank 1
answered on 17 Mar 2011, 07:38 PM

I have a workaround for the moment. Seems a little hackish so I'm still wondering if there's a better way.

I modified my AutoGeneratingColumn event to only create a new custom column when the number of columns in the RadGridView is less than expected.

private void recordGrid_AutoGeneratingColumn(object sender, Telerik.Windows.Controls.GridViewAutoGeneratingColumnEventArgs e)
{
    RadGridView rgv = sender as RadGridView;
    if (rgv.Columns.Count == 0)
    {
        String headerName = e.Column.Header.ToString();
        e.Column = new RecordColumn();
        e.Column.Header = headerName;
    }
    else
    {
        e.Cancel = true;
    }
}

In this demo case I'm only expecting 1 column ever so I just check for Columns.Count == 0. 

In my real application I have to first go get the number of expected columns from my data model and do Columns.Count < expectedColumnCount.

0
Accepted
Vlad
Telerik team
answered on 18 Mar 2011, 11:44 AM
Hi Fred,

The problem was fixed immediately and the fix will be part of our next internal build - Monday. I've added 2000 Telerik points to your account.

Regards,
Vlad
the Telerik team
Tags
GridView
Asked by
Fred
Top achievements
Rank 1
Answers by
Fred
Top achievements
Rank 1
Vlad
Telerik team
Share this question
or