17

我了解您可以将整个 DataGrid 或整个列设为仅就绪 (IsReadOnly = true)。但是,在单元级别,此属性仅准备就绪。但我确实需要这种粒度级别。在过去 DataGrid 是公共领域时,有一篇关于通过更改源代码将 IsReadOnly 添加到一行的博客,但现在我没有 DataGrid 的源代码。有什么解决方法?

禁用单元格(IsEnabled=false)几乎可以满足我的需要。但问题是您甚至无法单击禁用的单元格来选择行(我有全行选择模式)。

编辑:由于没有人回答这个问题,所以我想这不是一个容易解决的问题。这是一个可能的解决方法:使单元格不可编辑。唯一的问题是单击单元格不会选择行。我刚刚注意到,当单击禁用的单元格时,仍会触发 DataGrid 的 MouseDown 或 MouseUp 事件。在这个事件处理程序中,如果我能找出它单击的行,我可以以编程方式选择该行。但是,我不知道如何从DataGrid.InputHitTest. 有人可以给我一些提示吗?

4

11 回答 11

13

经过大量搜索和实验,使用 IsTabStop = False 和 Focusable = False 最适合我。

<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>
于 2015-09-09T07:57:02.140 回答
12

我遇到了同样的问题,单元格在某些行中应该是只读的,而在其他行中则不是。这是一个解决方法:

想法是在两个模板之间动态切换CellEditingTemplate,一个与 中的相同CellTemplate,另一个用于编辑。这使得编辑模式的行为与非编辑单元格完全相同,尽管它处于编辑模式。

以下是执行此操作的一些示例代码,请注意此方法需要DataGridTemplateColumn

首先,为只读和编辑单元格定义两个模板:

<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>

然后定义一个带有附加ContentPresenter层的数据模板,Trigger用于切换 的ContentTemplateContentPresenter这样就可以通过IsEditable绑定来动态切换上述两个模板:

<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>

高温高压

于 2011-08-19T02:21:05.380 回答
11

DataGridCell.IsReadOnly您可能认为可以绑定到一个属性,
例如像这样使用 XAML:

<!-- 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>

不幸的是,这不起作用,因为该属性不可写。
接下来您可能会尝试拦截和停止鼠标事件,但这不会阻止用户使用 F2 键进入编辑模式。

我解决这个问题的方法是在 DataGrid 上侦听,PreviewExecutedEvent然后有条件地将其标记为已处理。
例如,通过将类似于此的代码添加到我的 Window 或 UserControl 的构造函数(或另一个更合适的地方):

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;
        }
    }
}));

通过这样做,单元格仍然是可聚焦和可选择的。
但是除非您的模型项允许给定行,否则用户将无法进入编辑模式。
通过使用 DataGridTemplateColumn,您不会受到性能成本或复杂性的影响。

于 2011-10-02T00:24:40.717 回答
2

我通过在单元格中设置底层对象(例如 CheckBox)在我的应用程序中解决了这个问题 - IsHitTestVisible = false; 可聚焦 = 假;

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

“行”是一个 DataGridRow。IsHitTestVisible=false,表示您无法通过鼠标单击/选择/操作底层对象,但您仍然可以选择DataGridCell。Focusable=false,表示您无法使用键盘选择/操作底层对象。这给人一种只读单元格的错觉,但您仍然可以选择该单元格,并且我确定 DataGrid 是否设置为SelectionMode=FullRow然后单击“只读”单元格将选择整行。

于 2010-11-17T21:32:51.067 回答
1

我的解决方案是使用转换器绑定到 DataGridTemplateColumn。

<UserControl.Resources>
    <c:isReadOnlyConverter x:Key="isRead"/>
</UserControl.Resources>

   <DataGridTemplateColumn x:Name="exampleTemplate" Header="example:" Width="120" IsReadOnly="True">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                            <CheckBox x:Name="exampleCheckBox" VerticalAlignment="Center" IsEnabled="{Binding ElementName=exmpleTemplate, Path=IsReadOnly, Converter={StaticResource isRead}}"/>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>

和转换器:

class isReadOnlyConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        try
        {
            return !(bool)value;
        }
        catch (Exception)
        {
            return false;
        }
    }
于 2014-11-10T18:47:31.177 回答
1

这有点晚了,但是,我也在研究这个问题,这些解决方案运行良好,但我需要一些不同的东西,我做了以下工作,它的工作方式与我想要的和问题正在寻找的完全一样。

我本质上希望能够进入单元格的编辑模式,并使所有其他模板和命令逻辑相同,但不能编辑单元格。

所有这一切的解决方案是在 DataGridCell 样式中将 TextBox.IsReadOnly 属性设置为 true 并处理初始 keydown 事件

<Style TargetType="DataGridCell">
    <Setter Property="TextBox.IsReadOnly" Value="True"/>
    <EventSetter Event="PreviewKeyDown" Handler="cell_PreviewKeyDown"/>
</Style>

和后面的代码停止初始编辑

protected void cell_PreviewKeyDown(object sender, KeyEventArgs e)
{
    DataGridCell cell = sender as DataGridCell;
    if (cell.IsEditing == false && 
        ((Keyboard.Modifiers & ModifierKeys.Control) != ModifierKeys.Control)) //So that Ctrl+C keeps working
    {
        cell.IsEditing = true;
        e.Handled = true;
    }
}

希望这会有所帮助。

于 2015-03-24T17:06:46.200 回答
1

根据@sohum 评论,您可以在此处使用标记为答案的简化版回复。

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;
    }
}

您可以稍后将其用作附加属性行为。

于 2018-08-10T11:45:40.063 回答
0

为 DataGrid 获取可选择的只读文本单元格的一种方法是使用如下模板和样式:

<DataGrid>
<DataGrid.CellStyle>
    <Style TargetType="{x:Type DataGridCell}">                                        
        <Setter Property="BorderThickness" Value="0" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type DataGridCell}">
                    <Border Padding="0" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
                         <ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                        <TextBox BorderThickness="0" MouseDoubleClick="DataGrid_TextBox_MouseDoubleClick" IsReadOnly="True" Padding="5" Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content.Text}"/>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</DataGrid.CellStyle>

对于 CS 后端:

private void DataGrid_TextBox_MouseDoubleClick(object sender, MouseButtonEventArgs e)
    {
        (sender as TextBox).SelectAll();
    }
于 2013-06-21T10:47:15.643 回答
0

对我来说,最简单的解决方案是TextBoxEditingElementStyle.

<DataGridTextColumn Binding="{Binding MyValueProperty}">
    <DataGridTextColumn.EditingElementStyle>
        <Style TargetType="{x:Type TextBox}">
            <Style.Triggers>
                <DataTrigger Binding="{Binding MyReadonlyProperty}" Value="True">
                    <Setter Property="IsReadOnly" Value="True"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </DataGridTextColumn.EditingElementStyle>
</DataGridTextColumn>
于 2021-12-10T18:00:54.013 回答
0

您可以使用更简单的数据模板来做到这一点。

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

...

<DataGridTemplateColumn CellTemplate="{StaticResource MyTemplate}" />
于 2019-09-13T19:34:23.913 回答
0

就我而言,我使用的是 DataGridTextColumn。我在 Style 中的 ContentPresenter 上设置 IsEnabled 属性如下,它工作正常 -

     <DataGrid ItemsSource="{Binding Items}" AutoGenerateColumns="False">
        <DataGrid.Resources>
            <Style TargetType="{x:Type DataGridCell}">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type DataGridCell}">
                            <Grid Background="{TemplateBinding Background}" >
                                <ContentPresenter IsEnabled="{Binding Path=IsEditable}"/>
                            </Grid>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </DataGrid.Resources>
        <DataGridTextColumn Header="A" 
                            Binding="{Binding Path=A}"/>
    </DataGrid>
于 2018-09-22T14:01:19.060 回答