Insert a blank row into a Datagrid with dynamic columns

933 views Asked by At

I create the columns of my Silverlight DataGrid dynamically in the code behind using a List as follows:

private void BuildQuotationDGColumns(List<ProductCategory> ProdCatList)
        {
            // add a template column with drop down list of products
            DataGridTemplateColumn ProductColumn = new DataGridTemplateColumn();
            ProductColumn.Header="Choose Product";
            ProductColumn.CellTemplate=(DataTemplate) Resources["ProductDDLTemplate"];
            QuotationDG.Columns.Add(ProductColumn);
            // for each entity in ProdCatList add a text column
            foreach (ProductCategory ProdCat in ProdCatList)
            {
                DataGridTemplateColumn ProdCatColumn = new DataGridTemplateColumn();
                ProdCatColumn.Header = ProdCat.Name;
                ProdCatColumn.CellTemplate = (DataTemplate)Resources["MoneyTemplate"];
                ProdCatColumn.CellEditingTemplate = (DataTemplate)Resources["MoneyEditingTemplate"];
                QuotationDG.Columns.Add(ProdCatColumn);
            }

            insertDummyRow(ProdCatList);

        }

I need to insert a blank row in my Datagrid using insertDummyRow. Since the columns are dynamic and are only known in runtime, I need to create an entity whose attributes can be set in run time.

I thought of converting my ProdCatList into a Class, so that instances of this class would form the grid rows, but I couldn't understand how to do this conversion

EDIT:

Based on Bahman_Aries's solution below, I'm trying to add data into my row but I'm getting empty row and my data (column.Header.ToString()) isn't added. Here's my code:

 CultureInfo provider= new CultureInfo("en-US");
 Object[] myrow= new Object[QuotationDG.Columns.Count];
 int i=0;
 foreach(DataGridColumn column in QuotationDG.Columns)
 {
      myrow[i] = Convert.ChangeType(column.Header.ToString(), typeof(object), provider);
    i++;
 }
 MyData.Add(myrow);
 QuotationDG.ItemsSource = MyData;

Can you point me on what i'm doing wrong?

This is the implementation for the Grid Templates:

<UserControl.Resources>
        <DataTemplate x:Key="MoneyTemplate">
            <TextBlock></TextBlock>
        </DataTemplate>

        <DataTemplate x:Key="MoneyEditingTemplate">
            <TextBlock></TextBlock>
        </DataTemplate>
        <DataTemplate x:Key="ProductDDLTemplate">
            <ComboBox   />
        </DataTemplate>
    </UserControl.Resources>
1

There are 1 answers

11
Bahman_Aries On BEST ANSWER

Okey, let me clear up some confusion before we proceed:

Since the columns are dynamic and are only known in runtime, I need to create an entity whose attributes can be set in run time.

Not necessarily, you can use a list of objects.

I thought of converting my ProdCatList into a Class, so that instances of this class would form the grid rows

There is no need to create a complex data structure just to insert a blank row into the DataGrid, something as simple as QuotationDG.Items.Add(""); will do.

So from what I understand, either you're overcomplicating the issue or you did not provide enough information and I'm oversimplifying it! (If so please let me know so I can correct this straight away).

Anyhow, Since you defined a CellEditingTemplate I assume your grid cells are editable, therefore you can not use QuotationDG.Items.Add because it'll prevent editing. Instead you should define a list, add your data to it and then use it as ItemsSource of your DataGrid:

// Your data source
ObservableCollection<object[]> MyData = new ObservableCollection<object[]>();


// Insert a blank row into the data source
private void insertDummyRow()
{
    MyData.Add(new object[QuotationDG.Columns.Count]);
    QuotationDG.ItemsSource = MyData;
}

Edit:

Since there is no data-binding in your CellTemplates, nothing can be seen in your DataGrid. For this to work, when columns are creating dynamically you need to add corresponding DataBindings as well:

// Sample drop down list of products to show
public ObservableCollection<string> ProductList = new ObservableCollection<string> { "Item1", "Item2", "Item3" };
private void BuildQuotationDGColumns(List<ProductCategory> ProdCatList)
{
    // Define a DataGridComboBoxColumn 
    DataGridComboBoxColumn prodComboColumn = new DataGridComboBoxColumn();
    // Bind this column to the first item of the DataGrid.ItemsSource (e.g. MyData[0])
    prodComboColumn.SelectedItemBinding = new Binding("[0]");
    // Set ProductList as the ItemsSource of DataGridComboBoxColumn
    prodComboColumn.ItemsSource = ProductList;
    prodComboColumn.Header = "Choose Product";

    QuotationDG.Columns.Add(prodComboColumn);

    // For each entity in ProdCatList add a text column
    int i = 1;
    foreach (ProductCategory ProdCat in ProdCatList)
    {
        // Define a DataGridTextColumn 
        DataGridTextColumn ProdCatColumn = new DataGridTextColumn();
        ProdCatColumn.Header = ProdCat.Name;
        // Bind this column to the i-th item of the DataGrid.ItemsSource (e.g. MyData[i])
        ProdCatColumn.Binding = new Binding(string.Format("[{0}]", i));
        QuotationDG.Columns.Add(ProdCatColumn);
        i++;
    }
    insertDummyRow();
}

To see if UI shows any data, you can try my modified version of your add-data procedure:

private void Button_Click(object sender, RoutedEventArgs e)
{
    CultureInfo provider = new CultureInfo("en-US");
    Object[] myrow = new Object[QuotationDG.Columns.Count];
    int i = 0;
    foreach (DataGridColumn column in QuotationDG.Columns)
    {
        if (column is DataGridComboBoxColumn)
            myrow[i] = Convert.ChangeType(ProductList[0], typeof(object), provider);
        else
            myrow[i] = Convert.ChangeType(column.Header.ToString(), typeof(object), provider);

        i++;
    }
    MyData.Add(myrow);
    QuotationDG.ItemsSource = MyData;
}

To be sure that data entered by user is going to update the source (e.g. MyData) as well, set a break-point and check MyData for any changes after editing data-grid cells manually.