Search code examples
c#wpfdatagridisenableddatagridcell

WPF DataGrid disabled cell is receiving text input


Consider the following DataGrid having three columns:

enter image description here

When ever the age is -1 the corresponding cell gets disabled.

Ideally it shall not be possbile for the user to change the disabled cell value. However consider the user is in row 1 and the keyboard focus is in the corresponding cell of column Age, and presses enter, now the user types any number and the disabled cell get that value! Is this a desired behaviour? How can I avoid this behaviour?

enter image description here

To replicate issue:

  1. Select cell in row 1 of Age column
  2. Press enter
  3. Type a number

Reproducible code:

XAML:

<Window x:Class="wpf_behaviour.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="DataGridDetailsSample" Height="200" Width="400">
    <Grid Margin="10">
        <DataGrid Name="dgUsers" AutoGenerateColumns="False">
            <DataGrid.Columns>
                <DataGridTextColumn Header="ID" Binding="{Binding Id}"/>
                <DataGridTextColumn Header="Name" Binding="{Binding Name}" />
                <DataGridTextColumn Header="Age" Binding="{Binding Age}">
                    <DataGridTextColumn.CellStyle>
                        <Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
                            <Style.Triggers>
                                <DataTrigger Binding="{Binding Age}" Value="-1">
                                    <Setter Property="IsEnabled" Value="False"/>
                                    <Setter Property="ToolTip" Value="This filed is diabled."/>
                                    <Setter Property="Background" Value="LightGray"/>
                                </DataTrigger>
                            </Style.Triggers>
                        </Style>
                    </DataGridTextColumn.CellStyle>
                </DataGridTextColumn>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

Correspoinding cs:

using System.Collections.Generic;
using System.Windows;
using System.Windows.Documents;

namespace wpf_behaviour
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            List<User> users = new List<User>();
            users.Add(new User() { Id = 1, Name = "Kumar", Age = 10 });
            users.Add(new User() { Id = 2, Name = "Sameer", Age = -1 });
            users.Add(new User() { Id = 3, Name = "Danny", Age= 16 });

            dgUsers.ItemsSource = users;
        }

        public class User
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public int Age { get; set; }
        }
    }
}

Solution

  • I got the solution (added a PreviewKeyDown event handler) and here it is and I would like to know any better solution as well:

    private void DataGridCell_PreviewKeyDown(object sender, KeyEventArgs e)
    {
        try
        {
            DataGridCell cl = (DataGridCell)sender;
            //Get the Cell's parent row
            //using System.Windows.Media; for VisaualTreeHelper 
            var DataGridRowParent = VisualTreeHelper.GetParent(cl);
            while (DataGridRowParent != null && DataGridRowParent.GetType() != typeof(DataGridRow))
            {
                DataGridRowParent = VisualTreeHelper.GetParent(DataGridRowParent);
            }
            //Get the Row's parent DataGrid
            var DataGridParent = VisualTreeHelper.GetParent(DataGridRowParent);
            while (DataGridParent != null && DataGridParent.GetType() != typeof(DataGrid))
            {
                DataGridParent = VisualTreeHelper.GetParent(DataGridParent);
            }
    
            DataGrid dp = DataGridParent as DataGrid;
            //Get the CurrentCell value of DataGrid
            DataGridCellInfo cli = dp.CurrentCell;
    
            var CellContent = cli.Column.GetCellContent(cli.Item);
            if (CellContent != null)
            {
                //Get DataGridCell of DataGridCellInfo
                DataGridCell dgc = (DataGridCell)CellContent.Parent;
                if (dgc.IsEnabled == false)
                {
                    //If the key pressed is Enter or Tab allow
                    if (e.Key == Key.Enter || e.Key == Key.Tab)
                    {
                        e.Handled = false;
                        return;
                    }
                    //If any other key is pressed don't allow.
                    e.Handled = true;
                    return;
                }
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }
    }