Search code examples
c#wpfcomboboxreadonlydatagridtemplatecolumn

Make a cell with ComboBox readonly on certain conditions WPF DataGrid


What I have:

I have a DataGridTemplateColumn with a ComboBox:

<DataTemplate x:Key="ValuesCellTemplate">
      <TextBlock Text="{Binding Path=SelectedValue, Mode=OneWay}" />
</DataTemplate>
<DataTemplate x:Key="ValuesCellEditingTemplate">
      <ComboBox
            Name="ValuesComboBox"
            DisplayMemberPath="DisplayText"
            ItemsSource="{Binding Path=Value, Mode=OneWay}"
            SelectedValue="{Binding Path=SelectedValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
            SelectedValuePath="DisplayText" />
</DataTemplate>

I am autogenerating the columns, so the AutoGeneratingColumn event looks like this:

if (e.PropertyName == "First")
{
    var templateColumn = new DataGridTemplateColumn
    {
        Header = e.PropertyName,
        CellTemplate = (sender as FrameworkElement).FindResource("ValuesCellTemplate") as DataTemplate,
        CellEditingTemplate = (sender as FrameworkElement).FindResource("ValuesCellEditingTemplate") as DataTemplate
    };

    e.Column = templateColumn;
}

When Values (which is an ObservableCollection) is null I want the cell to be readonly, so it won't be able to enter CellEditing mode.

There are 2 options for the contents of this column:

  • a simple integer - SelectedValue
  • ObservableCollection<int> - Values

When Values has values inside, when double-clicking the cell (or the TextBlock)(so to say - entering CellEditing mode), a ComboBox should appear, otherwise not. That's basically it.

What I have tried:

I tried doing it this way:

<DataTemplate x:Key="ValuesCellTemplate">
      <TextBlock Text="{Binding Path=SelectedValue, Mode=OneWay}" />
</DataTemplate>
<DataTemplate x:Key="ValuesCellEditingTemplate">
      <ComboBox
            Name="ValuesComboBox"
            DisplayMemberPath="DisplayText"
            IsEnabled="{Binding HasItems, RelativeSource={RelativeSource Self}}"
            ItemsSource="{Binding Path=Value, Mode=OneWay}"
            SelectedValue="{Binding Path=SelectedValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
            SelectedValuePath="DisplayText" />
</DataTemplate>

But when I double-click on it, the TextBox turns into an empty readonly ComboBox (enters CellEditing mode). I just want for it to take no action (be readonly)(ONLY when Values is null).

What is the proper way to do that?

For the record, I am using MVVM pattern.


Solution

  • An easy way to prevent the DataGrid from entering the edit mode when you double-click on the TextBox would be to handle the PreviewMouseDown event for the cell:

    private void OnPreviewMouseDown(object sender, MouseButtonEventArgs e)
    {
        DataGridCell cell = (DataGridCell)sender;
        e.Handled = cell.DataContext is YourClass dataObject && !dataObject.Value.Any();
    }
    ...
    var templateColumn = new DataGridTemplateColumn
    {
        Header = e.PropertyName,
        CellTemplate = (sender as FrameworkElement).FindResource("ValuesCellTemplate") as DataTemplate,
        CellEditingTemplate = (sender as FrameworkElement).FindResource("ValuesCellEditingTemplate") as DataTemplate,
        CellStyle = (sender as FrameworkElement).FindResource("ReadOnlyCellStyle") as Style,
    };
    

    XAML:

    <Style x:Key="ReadOnlyCellStyle" TargetType="DataGridCell">
        <EventSetter Event="PreviewMouseDown" Handler="OnPreviewMouseDown" />
    </Style>