How to make WPF DataGridCell ReadOnly?

前端 未结 10 1804
你的背包
你的背包 2020-12-09 10:49

I understand you can make the whole DataGrid or a whole column readyonly (IsReadOnly = true). However, at cell level this property is ready only. But I do need this level of

相关标签:
10条回答
  • 2020-12-09 11:31

    After much searching and experimentation using IsTabStop = False and Focusable = False works best for me.

    <DataGridTextColumn Header="My Column" Binding="{Binding Path=MyColumnValue}">
        <DataGridTextColumn.CellStyle>
            <Style TargetType="DataGridCell">                                    
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Path=ReadOnly}" Value="True">                                                    
                        <Setter Property="IsTabStop" Value="False"></Setter>
                        <Setter Property="Focusable" Value="False"></Setter>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </DataGridTextColumn.CellStyle>
    </DataGridTextColumn>
    
    0 讨论(0)
  • 2020-12-09 11:34

    I've solved this problem in my application by setting the underlying object in the cell (eg. CheckBox) - IsHitTestVisible = false; Focusable = false;

    var cb = this.dataGrid.Columns[1].GetCellContent(row) as CheckBox;
    cb.IsHitTestVisible = false;
    cb.Focusable = false;
    

    "row" is a DataGridRow. IsHitTestVisible=false, means that you cant click/select/manipulate the underlying object via mouse, but you can still select the DataGridCell. Focusable=false, means that you can't select/manipulate the underlying object with the keyboard. This gives the illusion of a ReadOnly cell, but you can still select the cell and I'm sure if the DataGrid is set up to SelectionMode=FullRow then clicking the "read only" cell will select the entire row.

    0 讨论(0)
  • 2020-12-09 11:36

    Based on @sohum comment, here you can use simplified version of the response marked as answer.

    dataGrid.BeginningEdit += DataGrid_BeginningEdit;
    
    (...)
    
    private static void DataGrid_BeginningEdit(object sender, DataGridBeginningEditEventArgs e)
    {
        //Actual content of the DataGridCell
        FrameworkElement content = e.Column.GetCellContent(e.Row);
        MyObject myObject = (MyObject)content.DataContext;
    
        if (!myObject.CanEdit)
        {
            e.Cancel = true;
        }
    }
    

    You can use it later as Attached Property Behaviour.

    0 讨论(0)
  • 2020-12-09 11:39

    There is a property on DataGridCell.IsReadOnly that you might think you can bind to,
    e.g. using XAML like this:

    <!-- Won't work -->
    <DataGrid Name="myDataGrid" ItemsSource="{Binding MyItems}">
        <DataGrid.Resources>
            <Style TargetType="DataGridCell">
                <Setter Property="IsReadOnly" Value="{Binding MyIsReadOnly}" />
            </Style>
        </DataGrid.Resources>
        <!-- Column definitions... -->
    </DataGrid>
    

    Unfortunantly this won't work because this property is not writable.
    Next you might attempt to intercept and stop mouse events, but this won't prevent the user from entering edit mode using the F2 key.

    The way I sloved this was by listening for the PreviewExecutedEvent on the DataGrid and then conditionally flagging it as handled.
    E.g. by adding code similar to this to the constructor of my Window or UserControl (or another more suitable place):

    myDataGrid.AddHandler(CommandManager.PreviewExecutedEvent,
        (ExecutedRoutedEventHandler)((sender, args) =>
    {
        if (args.Command == DataGrid.BeginEditCommand)
        {
            DataGrid dataGrid = (DataGrid) sender;
            DependencyObject focusScope = FocusManager.GetFocusScope(dataGrid);
            FrameworkElement focusedElement = (FrameworkElement) FocusManager.GetFocusedElement(focusScope);
            MyRowItemModel model = (MyRowItemModel) focusedElement.DataContext;
            if (model.MyIsReadOnly)
            {
                args.Handled = true;
            }
        }
    }));
    

    By doing it like this the cells are still focusable and selectable.
    But the user will not be able to enter edit mode unless your model items allow it for the given row.
    And you will not suffer the performance costs or complexities by using the DataGridTemplateColumn.

    0 讨论(0)
  • 2020-12-09 11:39

    You can do this with a simpler data template.

    <DataGrid.Resources>
        <DataTemplate x:Key="MyTemplate" DataType="MyRowDataType">
            <TextBox Text="{Binding Value}" IsReadOnly="{Binding IsReadOnly}" />
        </DataTemplate>
    </DataGrid.Resources>
    

    ...

    <DataGridTemplateColumn CellTemplate="{StaticResource MyTemplate}" />
    
    0 讨论(0)
  • 2020-12-09 11:40

    I've encountered the same problem, the cell should be read-only in some rows but not in the others. Here is a workaround solution:

    The idea is to dynamically switch the CellEditingTemplate between two templates, one is the same as the one in the CellTemplate, the other is for editing. This makes the edit mode acts exactly the same as the non-editing cell although it is in edit mode.

    The following is some sample code for doing this, notice that this approach requires DataGridTemplateColumn:

    First, define two templates for read-only and editing cells:

    <DataGrid>
      <DataGrid.Resources>
        <!-- the non-editing cell -->
        <DataTemplate x:Key="ReadonlyCellTemplate">
          <TextBlock Text="{Binding MyCellValue}" />
        </DataTemplate>
    
        <!-- the editing cell -->
        <DataTemplate x:Key="EditableCellTemplate">
          <TextBox Text="{Binding MyCellValue}" />
        </DataTemplate>
      </DataGrid.Resources>
    </DataGrid>
    

    Then define a data template with additional ContentPresenter layer and use Trigger to switch the ContentTemplate of the ContentPresenter, so the above two templates can be switched dynamically by the IsEditable binding:

    <DataGridTemplateColumn CellTemplate="{StaticResource ReadonlyCellTemplate}">
      <DataGridTemplateColumn.CellEditingTemplate>
        <DataTemplate>
          <!-- the additional layer of content presenter -->
          <ContentPresenter x:Name="Presenter" Content="{Binding}" ContentTemplate="{StaticResource ReadonlyCellTemplate}" />
          <DataTemplate.Triggers>
            <!-- dynamically switch the content template by IsEditable binding -->
            <DataTrigger Binding="{Binding IsEditable}" Value="True">
              <Setter TargetName="Presenter" Property="ContentTemplate" Value="{StaticResource EditableCellTemplate}" />
            </DataTrigger>
          </DataTemplate.Triggers>
        </DataTemplate>
      </DataGridTemplateColumn.CellEditingTemplate>
    </DataGridTemplateColumn>
    

    HTH

    0 讨论(0)
提交回复
热议问题