Search code examples
c#wpfwpfdatagrid

WPF disable interacting with DataGrid's TemplateColumn for new rows before they are added


Consider a WPF DataGrid with DataGridTemplateColumn(s) and with user initiated adding CanUserAddRows="True" allowed, for example

<DataGrid AutoGenerateColumns="False" CanUserAddRows="True" ItemsSource="{Binding Options}">
    <DataGrid.Columns>
        <DataGridTemplateColumn>
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <RadioButton IsChecked="{Binding IsChecked}" GroupName="OptionsRad"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
        <DataGridTextColumn Header="Option" Binding="{Binding OptionName}"/>
    </DataGrid.Columns>
</DataGrid>

The RadioButton thanks to being hosted DataGridTemplateColumn can be interacted with without entering CellEditingMode, which is expected and desired.
There is, however, the problem that on the last, 'add new option', type-of-row the RadioButton can be interacted with even before new option is added (i.e. will be added name is entered). Possibly choosing non-existent option and moving focus elsewhere.
radio
How can I disable interacting with the template column before new row is added to bound collection?


Solution

  • You could use a converter to achieve what you are trying to do.

    I assumed you have a class or data type to represent your Option data and Options is a collection of those items.

    You could set IsEnabled on RadioButton to:

    IsEnabled="{Binding Path=Item, RelativeSource={RelativeSource AncestorType=DataGridRow"}, Converter={StaticResource DataToEnabledConverter}}"
    

    And, the converter code would look like:

    public class DataToEnabledConverter : IValueConverter
    {
         public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
         {
             return value is Option;
         }
    
         public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
         {
             throw new NotImplementedException();
         }
    }
    

    Your full XAML would look like:

        <DataGrid AutoGenerateColumns="False" CanUserAddRows="True" ItemsSource="{Binding Options}">
            <DataGrid.Columns>
                <DataGridTemplateColumn>
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <RadioButton IsChecked="{Binding IsChecked}" GroupName="OptionsRad" 
                                         IsEnabled="{Binding Path=Item, RelativeSource={RelativeSource AncestorType=DataGridRow"}, Converter={StaticResource DataToEnabledConverter}}"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
                <DataGridTextColumn Header="Option" Binding="{Binding OptionName}"/>
            </DataGrid.Columns>
        </DataGrid>
    

    This works because Item property on DataGridRow for new rows would be of type NamedObject, not your data type.