4

In our data grid we're using an ItemTemplateSelector to switch between two data templates based on the data bound to a particular cell.

As the number of columns depends on the current data set we're using AutoGenerateColumns in our DataGrid.

It appears that this particular combination does not work well -
the template selector isn't even called.

Can we use the template selector in a data grid where columns are created automatically?

More specifically: Is this possible using XAML only w/o putting logic into the code-behind file or using custom behaviours?

Our data grid definition is fairly trivial:

 <DataGrid
     ItemTemplateSelector="{StaticResource myCustomDataTemplateSelector}"
     ItemsSource="{Binding MyData}">
     <DataGrid.Columns>
     </DataGrid.Columns>
 </DataGrid>

The item template selector definition:

<UserControl.Resources>
    <ResourceDictionary>
        <helpers:CustomDataTemplateSelector x:Key="myCustomDataTemplateSelector"/>
    </ResourceDictionary>
</UserControl.Resources>
cacau
  • 3,606
  • 3
  • 21
  • 42
  • Are you sure your myCustomDataTemplateSelector is instantiated in resources? Also, where are you defining the templates – Walt Ritscher Dec 29 '14 at 08:48
  • Suppose so - definition added to the question. The DataTemplates are defined in that same resources section in the same file - but it doesn't seem to get that far.. – cacau Dec 29 '14 at 08:53

2 Answers2

6

First,

ItemTemplate and ItemTemplateSelector are inherited properties which are purposely ignored in the DataGrid since they don't really apply to DataGrid in the way that they were meant to in ItemsControl.

Secondly, if you mean that you want to modify cell templae based on its value, you are looking for CellTemplateSelector, on a DataGridTemplateColumn.

However, when you auto-generate columns, it already chooses the underlying types automatically.

You can override that behavior in GeneratingColumns event.

See this: Force DataTemplateCell with CellTemplateSelector in WPF DataGrid Autogenerated columns

If you need more control, you might want to take a look at https://zamjad.wordpress.com/2011/09/17/datagrid-with-dynamic-columns-revisited/

Community
  • 1
  • 1
Erti-Chris Eelmaa
  • 25,338
  • 6
  • 61
  • 78
  • Thanks for the hint! Setting the template selector in a behaviour now so it's being triggered - still, the `item` parameter in SelectTemplate() is always null – cacau Dec 29 '14 at 13:00
  • @cacau: Always, or only for the first pass? The method should be called twice for each column (one to set up logical tree, second to render). http://stackoverflow.com/questions/4268409/no-parameters-are-passed-to-selecttemplate-of-custom-datatemplateselector-why – Erti-Chris Eelmaa Dec 29 '14 at 15:25
0

I recently ran into this problem and solved it this way:

we can inherit the class DataGridBoundColumn

public class DataGridProcessContainerColumn : DataGridBoundColumn
{
    public DataTemplate ContentTemplate { get; set; }

    protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem)
    {
        throw new NotImplementedException();
    }

    protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
    {
        var control = new ContentControl();
        control.ContentTemplate = ContentTemplate;
        BindingOperations.SetBinding(control, ContentControl.ContentProperty, Binding);
        return control;
    }
}

Next, in the event handler, where the column is generated, I do:

private void DataGrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
    DataTemplate template = null;

    // Four lines below replace the DataTemplateSelector
    // You need to select the desired template according to your conditions
    if (e.PropertyType.IsAssignableFrom(typeof(IEnumerable<MyClass2>)))
        template = (DataTemplate)Resources["MyClass2CollectionTemplate"];
    else if (e.PropertyType.IsAssignableFrom(typeof(MyClass2)))
        template = (DataTemplate)Resources["MyClass2Template"];

    if (template != null)
    {
        var col = new DataGridProcessContainerColumn();
        col.Binding = (e.Column as DataGridBoundColumn).Binding;
        col.ContentTemplate = template;
        col.Header = e.Column.Header;
        e.Column = col;
    }
}

In the resources of the window I have the corresponding templates.

It is possible to do through DataTemplateSelector, but there was no time.

ChrisM
  • 1,576
  • 6
  • 18
  • 29
iRumba
  • 101
  • 5