0

I am trying to have a DataGrid that shows a user controls in each cell of it's rows. highliting that the DataGrid have to be dynamic because columns count is dynamic for each case of use.

In my xaml code (XAML) i have this as a declaration of the DataGrid :

<Grid Grid.Column="1" Margin="0,10,0,0">
      <DataGrid AutoGenerateColumns="False" x:Name="planningTable" FrozenColumnCount="1"/> 
</Grid>

My user controle look like this (the UserControl is already done and it works perfectly): enter image description here

As a result of the DataGrid i want to have this UserControl in each Cell of the DataGrid it means that DataGrid Rows have to show this UserControl in each Cell. i've searched a lot for this trick but seems that DataGrid can't host a UserControl in cells.

I want to have the C# code that do this, please no XAML code because it is all dynamic !!

AouledIssa
  • 2,528
  • 2
  • 22
  • 39
  • You can have it in XAML way (That too neat and dynamic will work). But you need to add more details that how many columns and rows you want? Is ItemsSource bound to some collection? – Rohit Vats May 31 '14 at 09:05
  • Yes it's true that can have this dynamically with XAML through DataBinding. but i want to have the c# code that do this beacause i'm not using data Binding! – AouledIssa May 31 '14 at 09:08

1 Answers1

1

Like I mentioned in comment, you can do that dynamically with XAML only. Doing this in code behind, you might end up writing lot of code and loose upon important features of WPF. Most importantly UI Virtualization if you create rows manually yourself.


In case you don't want any binding support and want to show plain dataGrid with all cells filled with your UserControl, you can do this way:

It will show 2 columns and 100 rows filled with your custom user control:

<Grid>
    <Grid.Resources>
        <ObjectDataProvider x:Key="EnumerableRange"
                 xmlns:sys="clr-namespace:System;assembly=mscorlib"
                 xmlns:linq="clr-namespace:System.Linq;assembly=System.Core"
                 ObjectType="{x:Type linq:Enumerable}" MethodName="Range">
            <ObjectDataProvider.MethodParameters>
                <sys:Int32>1</sys:Int32>
                <sys:Int32>100</sys:Int32>
            </ObjectDataProvider.MethodParameters>
        </ObjectDataProvider>
    </Grid.Resources>
    <DataGrid AutoGenerateColumns="False" IsReadOnly="True"
            CanUserAddRows="False"
            CanUserDeleteRows="False"
            ItemsSource="{Binding Source={StaticResource EnumerableRange}}">
        <DataGrid.Columns>
            <DataGridTemplateColumn Header="Test1">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <local:SampleUserControl/>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
            <DataGridTemplateColumn Header="Test2">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <local:SampleUserControl/>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
        </DataGrid.Columns>
    </DataGrid>
</Grid>

UPDATE

In case you want to set columns dynamically, like I mentioned in my comments you have to set AutoGenerateColumns to False and manually add Columns collection. Instead of creating DataGridTemplateColumns manually you can declare it under resources section of DataGrid and use it in code behind.

XAML:

<Grid>
    <Grid.Resources>
        <ObjectDataProvider x:Key="EnumerableRange"
            xmlns:sys="clr-namespace:System;assembly=mscorlib"
            xmlns:linq="clr-namespace:System.Linq;assembly=System.Core"
            ObjectType="{x:Type linq:Enumerable}" MethodName="Range">
            <ObjectDataProvider.MethodParameters>
                <sys:Int32>1</sys:Int32>
                <sys:Int32>100</sys:Int32>
            </ObjectDataProvider.MethodParameters>
        </ObjectDataProvider>
    </Grid.Resources>
    <DataGrid AutoGenerateColumns="False"
                x:Name="dataGrid"
                IsReadOnly="True"
                CanUserAddRows="False"
                CanUserDeleteRows="False"
                ItemsSource="{Binding Source={StaticResource EnumerableRange}}">
        <DataGrid.Resources>
            <DataGridTemplateColumn x:Key="TemplateColumn" x:Shared="False">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <local:SampleUserControl/>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
        </DataGrid.Resources>
    </DataGrid>
</Grid>

Code behind

public partial class MainWindow : Window
{
    private void CreateDataGridColumns()
    {
        for (int i = 0; i < 10; i++) // Change number of columns here.
        {
            DataGridTemplateColumn templateColumn = 
                  (DataGridTemplateColumn)dataGrid.Resources["TemplateColumn"];
            templateColumn.Header = String.Format("Test {0}", i + 1);
            dataGrid.Columns.Add(templateColumn);
        }
    }

    public MainWindow()
    {
        InitializeComponent();
        CreateDataGridColumns();
    }
}
Rohit Vats
  • 79,502
  • 12
  • 161
  • 185
  • Thank you soo much @Rohit it works perfectly !!! i'm soo greatfull Can you please tell me how to make the columns count to be Dynamic for example some times it's 6 Columns and X columns in an other time – AouledIssa May 31 '14 at 10:02
  • can you tell please how to make the DataGrid columns Count to be Dynamic ?? i will be greatfull for that. – AouledIssa May 31 '14 at 10:16
  • To make Columns to be dynamic, you have to set `AutoGenerateColumns=True` on dataGrid and bind ItemsSource with binding object. It will generate columns equal to number of properties in underlying object. – Rohit Vats May 31 '14 at 10:22
  • You can refer to this as well if not interested in creating underlying object for ItemsSource - http://stackoverflow.com/questions/1983033/how-do-i-dynamically-generate-columns-in-a-wpf-datagrid. – Rohit Vats May 31 '14 at 10:24
  • Seems that i can't do that because the ItemsSource is binded to rows :EnumerableRange do you have an other solution ? – AouledIssa May 31 '14 at 10:32
  • 1
    Other way is to manually add the columns from code behind on dataGrid load. But like I said if you do that, you will lost UI virtualization i.e. if you add for example 10 columns you will see some lag of that being rendered on UI. But if you manually add 10 columns in XAML, it will show instantly. – Rohit Vats May 31 '14 at 10:45
  • So if i understand, i have to perform multiple binding where one is for columns and the second is for the rows ? – AouledIssa May 31 '14 at 12:08
  • 1
    I have updated with another approach in answer. See if that works for you. (Obviously binding is the better way but this will work too in case you don't want to bind anything). – Rohit Vats May 31 '14 at 12:24
  • 1
    Thank you soooooooooooo much brother !!! You are breliant !!!! thank you sooo much !! – AouledIssa May 31 '14 at 12:37
  • Do you have any idea about how to have text in each row Header ? i mean i have a list of strings that contains names and it must be put in the header of each row. – AouledIssa May 31 '14 at 13:46