user1665567
user1665567

Reputation:

Data bound DataGrid with custom column headers

My question seems rather simple:

How can one add custom headers to a data bound DataGrid in WPF?

Why am I asking this question? Well, because I've fitted my DataGrid (which is generated in code-behind) with a dynamic itemssource, bound to an ienumerable 'list'. This works perfectly fine, although it uses the property names as column headers.

To improve readability I simply want to assign custom headers to the columns, however... My idea was to supply a datagrid with the columns already defined, and let the itemssource fill the rows. But itemssource deals with the rows, as well as the columns.

I hope you can see my problem here. Help is greatly appreciated!

Upvotes: 2

Views: 4091

Answers (5)

Arthur Nunes
Arthur Nunes

Reputation: 7058

The DataGrid class has a property to configure the column generation behavior, called "AutoGenerateColumns" (link). To disable this behavior just set it to false.

You have a better control of the shape of your DataGrid if you do it in xaml. An example:

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    xmlns:local="clr-namespace:WpfApplication1"
    Title="MainWindow"
    Width="525"
    Height="350">
<Grid>                  
    <DataGrid AutoGenerateColumns="False" >
        <DataGrid.Columns>              
            <DataGridTextColumn Header="MyHeader1" Binding="{Binding MyProperty1}"/>
            <DataGridTextColumn Binding="{Binding MyProperty2}">
                <DataGridTextColumn.Header>
                    <Button Content="A button"/>
                </DataGridTextColumn.Header>
            </DataGridTextColumn>
        </DataGrid.Columns>
    </DataGrid>
</Grid>

As you can see, the "Header" property of a column definition will accept any content, texts or controls, if you want to customize it further.

EDIT

An example of how to do it from the code behind, in the Window's Loaded event:

void MainWindow_Loaded(object sender, RoutedEventArgs e)
    {
        var dataGrid = new DataGrid();
        dataGrid.AutoGenerateColumns = false;

        // For each column you want
        var column1 = new DataGridTextColumn();
        column1.Header = "MyHeader";
        column1.Binding = new Binding("MyProperty");
        dataGrid.Columns.Add(column1);

        // LayoutRoot is the main grid of the Window
        this.LayoutRoot.Children.Add(dataGrid);


        // Let's test to see if the binding is working
        IEnumerable<DummyClass> testEnumerable = new List<DummyClass>(){
            new DummyClass(){MyProperty= "Element1"},
            new DummyClass(){MyProperty= "Element2"},
        };

        dataGrid.ItemsSource = testEnumerable;
    }

Upvotes: 3

Bob.
Bob.

Reputation: 4002

If you're creating a DataGrid from code-behind, you can specify everything that you bind with DataContext and Bindings.

Let's say we have a DataGrid myDataGrid.

Bind the ItemsSource to myDataGrid:

 Binding dataGridItemsSourceBinding = new Binding("MyItemsSourceName");
 myDataGrid.SetBinding(DataGrid.ItemsSourceProperty, datagridItemsSourceBinding);

Create a DataGridTemplateColumn

 DataGridTemplateColumn templatecolumn = new DataGridTemplateColumn() {
      Header = "myColumnName", // Add the name of your column here
 };

Create the Data Template for when you are displaying the value in the DataCell for the DataGrid Column

 // Displaying Template for when you display the DataCell in the DataGridColumn
 // Create a Data Template for when you are displaying a DataGridColumn
 DataTemplate textBlockTemplate = new DataTemplate();
 // Create a Framework Element for the DataGridColumn type (In this case, a TextBlock)
 FrameworkElementFactory textBlockElement = new FrameworkElementFactory(typeof(TextBlock));
 // Create a Binding to the value being displayed in the DataGridColumn
 Binding textBlockBinding = new Binding("myPropertyName");
 // Assign the Binding to the Text Property of the TextBlock
 textBlockElement.SetBinding(TextBlock.TextProperty, textBlockBinding);
 // Set the DataGridColumn to stretch to fit the text
 textBlockElement.SetValue(TextBlock.HorizontalAlignmentProperty, HorizontalAlignment.Stretch);
 // Add the TextBlock element to the Visual Tree of the Data Template
 textBlockTemplate.VisualTree = textBlockElement;
 // Add the Data Template to the DataGridColumn Cell Template
 templatecolumn.CellTemplate = textBlockTemplate;

Create the Data Template for when you are editing the value in the DataCell for the DataGrid Column

 // Editing Template for when you edit the DataCell in the DataGridColumn
 // Create a Data Template for when you are displaying a DataGridColumn
 DataTemplate textBoxTemplate = new DataTemplate();
 // Create a Framework Element for the DataGrid Column type (In this case, TextBox so the user can type)
 FrameworkElementFactory textBoxElement = new FrameworkElementFactory(typeof(TextBox));
 // Create a Binding to the value being edited in the DataGridColumn
 Binding textBoxBinding = new Binding("myPropertyName");
 // Assign the Binding to the Text Property of the TextBox
 textBoxElement.SetBinding(TextBox.TextProperty, textBoxBinding);
 // Set the DataGridColumn to stretch to fit the text
 textBlockElement.SetValue(TextBlock.HorizontalAlignmentProperty, HorizontalAlignment.Stretch);
 // Add the TextBox element to the Visual Tree of the Data Template
 textBoxTemplate.VisualTree = textBoxElement;
 // Add the Data Template to the DataGridColumn Cell Editing Template
 templatecolumn.CellEditingTemplate = textBoxTemplate;

Add the completed DataGridColumn to your DataGrid

 // Add the completed DataGridColumn to your DataGrid
 myDataGrid.Columns.Add(templateColumn);

Upvotes: 1

User1551892
User1551892

Reputation: 3384

If you know that every time you will get same data then you can define columns headers and forget about rows. I assume that you have list of object of same type and it means you will have same properties to display in each row. Things will be simple if you will provide some example of your Enumerable.

You can define column headers in XAML file and also in properties of DataGrid in Columns Property.

Before doing this you have to bind you list with itemsource of Datagrid.

Upvotes: 0

Fede
Fede

Reputation: 44068

Handle the AutoGeneratingColumn event of the DataGrid and then you can create some kind of map between the default column names (Property names) and your custom headers.

For example:

string headername = e.Column.Header.ToString();

if (headername == "MiddleName")
     e.Column.Header = "Middle Name";

Edit: taken from MDSN

Upvotes: 1

paparazzo
paparazzo

Reputation: 45106

If using AutoGenerate see link below

DataGrid.AutoGenerateColumns

Or don't AutoGenerate and build the binding.
If the columns are dynamic then must you code behind.
If the columns are statics then can use XAML.

<DataGrid Name="DG1" ItemsSource="{Binding}" AutoGenerateColumns="False" >
     <DataGrid.Columns>
          <DataGridTextColumn Header="First Name"  Binding="{Binding FirstName}"/>   

Upvotes: 0

Related Questions