Search code examples
c#wpfdatagridviewdatagriddatagridviewcolumn

Add StackPanel to WPF DataGrid at runtime


I have a Datagrid that is being built dynamically from incoming data using the following:

TableData = JObject.Parse(File.ReadAllText(@"Datainfo.json"));
var listCols = new List<DataColumn>();
var rawData = new DataTable();
foreach (dynamic item in TableData.data)
{
    string columnName = item.Column;
    var column = new DataColumn(columnName);
    string DataType = item.DataType;
    if (DataType == "Int" )
    {
        column.DataType = Type.GetType("System.Int32");
    }
    else
    {
        column.DataType = Type.GetType("System.String");
    }
    column.Unique = false;
    column.AllowDBNull = true;
    column.AutoIncrement = false;
    listCols.Add(column);
    rawData.Columns.Add(column);
}

Then I am pushing it to the DataGrid like this:

    DataTable ETL = null;
    ETL = rawData;
    ETL.DefaultView.AllowEdit = true;
    DataGridView.DataContext = ETL;

I would like to add a StackPanel to each column that includes a TextBox for the Column Name, and a dropdown that has various datatypes in it. It would then have a Apply / Cancel option.

I have been trying to follow similar solutions for adding Expanders to Grids, but I can't figure out how to apply it to a DataGrid since it doesn't have a .Children() to .Add() to. https://www.codeproject.com/Questions/877973/How-Do-I-Add-A-Stackpanel-To-An-Expander-Header-Vi

Is there a way to do what I am asking? I also tried to hide the header row and control the first two rows, but then when I tried loading up the header into a Int column, I get an error, so obviously that isn't a good idea.


Solution

  • If you are adding this to the column header than you must add it as a HeaderTemplate. Lets say this is the XAML...

    <Window x:Class="testtestz.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow"
            xmlns:local="clr-namespace:testtestz"
            xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity">
        <Grid>
            <ListView>
                <ListView.View>
                    <GridView x:Name="myGrid">
                        <GridViewColumn Header="Id"/>
                        <GridViewColumn Header="Name"/>
                        <GridViewColumn Header="Date"/>
                    </GridView>
                </ListView.View>
            </ListView>
        </Grid>
    </Window>
    

    Then you would do this in the code behind...

    using System;
    using System.Windows;
    using System.Windows.Controls;
    
    namespace testtestz
    { 
    
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
    
            protected override void OnContentRendered(EventArgs e)
            {
                base.OnContentRendered(e);
    
                var cBox = new FrameworkElementFactory(typeof(ComboBox));
    
                myGrid.Columns[0].HeaderTemplate = new DataTemplate() { VisualTree = cBox };
            }
        }
    }
    

    This is just a showcase of how to do it. Of course you would have to play with some layout, sizes and simillar stuff to get it to a reasonable point but I hope it helps.