Search code examples
datagridwinui-3winuidatatemplateselector

WinUI 3 Data Grid Having Different Formatting For Each Cell Using the DataTemplateSelector Class


I'm trying to create a simple data grid in WinUI 3 that uses custom DataTemplate that vary for the second column, creating different formatting for the second column's cells depending on the data type of the cell's data. A boolean would have a CheckBox and a string would have a TextBox.

I'm extending the DataTemplateSelector class to achieve this, per this page: https://learn.microsoft.com/en-us/windows/apps/design/controls/data-template-selector

The problem is, my extension's override DataTemplateSelectorExt.SelectTemplateCore() method shown below doesn't even run, so I can't even test if the template code is good. There are no errors, but the second column of the data grid only shows the namespace of the CustomInfo class: ...ViewModels.CustomInfo.

My first question is, what is preventing SelectTemplateCore() from running and providing the second column with a custom DataTemplate?

XAML

       <Page.Resources>
            <local:DataTemplateSelectorExt
                x:Key="templateselctor"
                CheckBoxTemplate="{StaticResource CheckBoxTemplateResource}"
                TextBlockTemplate="{StaticResource TextBlockTemplateResource}"
                TextBoxTemplate="{StaticResource TextBoxTemplateResource}" />

        <DataTemplate x:Key="TextBlockTemplateResource" x:DataType="x:String">
            <Grid>
                <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" />
            </Grid>
        </DataTemplate>

        <DataTemplate x:Key="TextBoxTemplateResource" x:DataType="x:String">
            <Grid>
                <TextBox Text="{x:Bind}" />
            </Grid>
        </DataTemplate>

        <DataTemplate x:Key="CheckBoxTemplateResource" x:DataType="x:Boolean">
            <Grid>
                <CheckBox HorizontalAlignment="Center" VerticalAlignment="Center" IsChecked="{x:Bind}" />
            </Grid>
        </DataTemplate>

    </Page.Resources>

    <Grid>
        <DataGrid
            x:Name="dataGrid1"
            ItemsSource="{x:Bind ViewModel.CustomInfoItems}" >
            <DataGrid.Columns>
                <GridTextColumn
                    MappingName="CFieldDisplayName" />
                <GridTemplateColumn
                    CellTemplateSelector="{StaticResource templateselctor}"
                    MappingName="CFieldValue" />
            </DataGrid.Columns>
        </DataGrid>
    </Grid>

Code Behind

    public sealed partial class MyPage : Page
    {
        public DataGridViewModel ViewModel { get; }

        public MyPage()
        {
            this.InitializeComponent();

            ViewModel = new DataGridViewModel();
        }
    }


    public class DataTemplateSelectorExt : DataTemplateSelector
    {
        public DataTemplate TextBlockTemplate { get; set; }
        public DataTemplate TextBoxTemplate { get; set; }
        public DataTemplate CheckBoxTemplate { get; set; }

        protected override DataTemplate SelectTemplateCore(object item) 
        { //This line is never his with a breakpoint
            if (item == null)
            {
                return TextBlockTemplate;
            }
            else if (item.GetType() == typeof(string))
            {
                return TextBoxTemplate;
            }
            else if (item.GetType() == typeof(bool))
            {
                return CheckBoxTemplate;
            }
            else
            {
                return TextBoxTemplate;
            }
        }
    }

ViewModel

        public DataGridViewModel()
        {
            CustomInfoItems = new ObservableCollection<CustomInfo>();
            this.GenerateCutomInfoItems();
        }

        private void GenerateCutomInfoItems()
        {
            CustomInfoItems.Add(new CustomInfo() { CFieldDisplayName = "Custom TextBox Item", CFieldValue = "String Value" });
            CustomInfoItems.Add(new CustomInfo() { CFieldDisplayName = "Custom CheckBox Item", CFieldValue = true });
        }

    public class CustomInfo
    {
        public string CFieldDisplayName { get; set; }
        public object CFieldValue { get; set; }
    }

Solution

  • As you can see in the doc, the DataTemplateSelector, the DataTemplateSelector has two overridable methods.

    • SelectTemplateCore(Object)
    • SelectTemplateCore(Object, DependencyObject)

    In your case, try overriding the second one instead.