禁用 WPF DataGrid 中的选择功能

58

我该如何禁用 WPF Toolkit 的 DataGrid 中的选择功能? 我尝试修改适用于 ListView 的解决方案(来自 WPF ListView turn off selection),但那并不起作用:

<tk:DataGrid>
    <tk:DataGrid.ItemContainerStyle>
        <Style TargetType="{x:Type tk:DataGridRow}">
            <Setter Property="Focusable" Value="false"/>
        </Style>
    </tk:DataGrid.ItemContainerStyle>
    <tk:DataGrid.CellStyle>
        <Style TargetType="{x:Type tk:DataGridCell}">
            <Setter Property="Focusable" Value="false"/>
        </Style>
    </tk:DataGrid.CellStyle>
</tk:DataGrid>
13个回答

48

最好的方法是只覆盖行和单元格的样式。

<DataGrid.Resources>
    <ResourceDictionary>
        <Style x:Key="{x:Type DataGridCell}" TargetType="{x:Type DataGridCell}">
            <Setter Property="Background" Value="{x:Null}" />
            <Setter Property="BorderBrush" Value="{x:Null}" />
            <Style.Triggers>
                <Trigger Property="IsSelected" Value="True">
                    <Setter Property="Background" Value="{x:Null}" />
                    <Setter Property="BorderBrush" Value="{x:Null}" />
                </Trigger>
            </Style.Triggers>
        </Style>
        <Style TargetType="{x:Type DataGridRow}">
            <Setter Property="Background" Value="{x:Null}" />
            <Setter Property="BorderBrush" Value="{x:Null}" />
            <Style.Triggers>
                <Trigger Property="IsSelected" Value="True">
                    <Setter Property="Background" Value="{x:Null}" />
                    <Setter Property="BorderBrush" Value="{x:Null}" />
                </Trigger>
            </Style.Triggers>
        </Style>
    </ResourceDictionary>
</DataGrid.Resources>

2
这完全禁用了选择。我不得不将“{x:Null}”替换为“Transparent”以保持选择功能正常。这是Snuggles先生推荐的方法。 - OneWorld
12
请注意,在触发器中不要忘记设置 <Setter Property="Foreground" Value="Black"/>,否则选择的文本将默认为白色。请注意保持原意,尽可能让翻译更加通俗易懂,不提供解释或其他额外信息。 - JiBéDoublevé
4
我刚刚做了这件事,但是没有使用硬编码的值,而是将其放在DataGridCell的触发器中:<Setter Property="Foreground" Value="{Binding RelativeSource={RelativeSource Self}, Path=Foreground}"/>,这会将其设置为它已经存在的值。奇怪的是,在列定义上明确设置颜色也会移除颜色更改,而不需要setter。 - Xcelled
1
如果您想保留默认样式(例如Material Design)的设置,则可以将其添加到“style”标签中:BasedOn = "{StaticResource {x:Type DataGridCell}}"BasedOn = "{StaticResource {x:Type DataGridRow}}" ...结果只会删除边框,而不是整个默认样式。 - Beauty
1
你对所有控件仍然变成蓝色该怎么办?每个单元格中的文本块背景都会变成蓝色,而且在数据模板中有下拉菜单和按钮,当选择行时它们会有蓝色边框。 - Matt Gregory

35

要完全禁用DataGrid中行的选择,您可以执行以下操作:

<DataGrid>
    <DataGrid.RowStyle>
        <Style TargetType="DataGridRow">
            <Setter Property="IsHitTestVisible" Value="False"/>
        </Style>
    </DataGrid.RowStyle>
    <!--Other DataGrid items-->
</DataGrid>

相较于设置 <Setter Property="IsEnabled" Value="False"/>,这种方法可能更为优越,因为前者会导致行的样式发生变化。同时,这种方法并不会禁用右键点击时出现的上下文菜单。

最后需要注意的是,将"IsHitTestVisible" 设置为“False”会禁用与行的所有交互,包括编辑。

但是,如果你只想在选中行时更改行的样式,请查看这里的答案。


2
这个答案真的救了我的命! - polfosol ఠ_ఠ
虽然这是旧答案,但我想对此发表评论。我的解决方案是使用具有单独 ViewModel 的行。为了完全禁用 datagrid,您可以使用 DataGrid.Style 和 TargetType =“DataGrid”。因为我需要控制何时允许选择项目,所以我使用 Value =“{Binding SomeProperty}”,然后该属性必须在 DataContext 上。如果在使用 RowStyle 设置时该属性位于主 DataContext 上,则会给我带来绑定错误。 - Paul Palmpje
这个可以运行,但会阻止点击任何按钮。 - Rye bread
@Rugbrød:“需要注意的是,将“IsHitTestVisible”设置为“False”会禁用所有与行的交互,包括编辑。”这包括点击按钮。 - JoshuaTheMiller

25

只需在 DataGrid 定义中添加IsHitTestVisible="False"


34
这会使垂直滚动条无法响应鼠标。 - edtheprogrammerguy
3
非常好用...如果将该值绑定到一个INPC属性上,那么您可以有选择地指定哪些行是可选的 :-) - Riegardt Steyn
2
除了垂直滚动条问题之外,这也会禁用子控件的鼠标点击。 - Slate

12

以上所有方法都是易于实现的小技巧,但它们并没有完全解决问题。其他答案告诉我们如何取消用户选择的内容或隐藏用户已选择的内容。

然而,我理解为什么会给出这些答案。提供真正的解决方案不容易。

真正的解决方案是在一开始就防止选择,这并不简单,但通过几个简单的步骤是可行的。

回答: 1. 您需要复制Expression Blend中的样式(或在其他地方找到样式的副本)。 2. 更改单个ItemPresenter设置。 对于我来说,仅在ItemPresenter上设置IsHitTestVisible =“False”就足够了。

如果您需要更多详细信息或完整的操作说明,请参见我的博客文章:

如何禁用WPF DataGrid中的行选择?


14
这并不完全正确 - 它会阻止在“DataGridCell”上发生的点击,而这通常不是期望的行为。 - Zero
1
同意。总有一天我会找到一个禁用选择但允许点击的解决方案。 - Rhyous

8
如Sonic Soul在这里指出的那样,viky的解决方案实际上不起作用。
以下是真正可行的代码,用于禁用DataGrid中的选择:
grid.SelectionChanged += (obj, e) => 
  Dispatcher.BeginInvoke(DispatcherPriority.Render, new Action(() => 
    grid.UnselectAll())); 

1
这个方法应该与设置DataGrid的SelectionMode属性为“Single”相结合...否则在事件触发之前,您可以选择多个单元格。 - Sherlock

6
我发现唯一正确的方法是禁用DataGrid行样式中的IsHitTestVisible属性。
尽管名称如此,单击事件仍将注册。确保您不会更改整个DataGrid上的此属性,除非您还想禁用滚动。
通过静态资源中的新样式以干净的方式执行此操作(根据需要复制其他Setter)。
        <Style x:Key="DataGridUnselectableRowStyle" TargetType="{x:Type DataGridRow}">
            <Setter Property="IsHitTestVisible" Value="False"/>
        </Style>

然后将其绑定到您的DataGrid上

        <DataGrid
            RowStyle="{StaticResource DataGridUnselectableRowStyle}" >
            <!-- Contents -->
        </DataGrid>

4

如果您正在使用交替颜色:

<Style TargetType="{x:Type DataGrid}">
    <Setter Property="RowBackground" Value="#badeee"/>
    <Setter Property="AlternationCount" Value="2" />
    <Setter Property="AlternatingRowBackground" Value="#92cce5"/>
</Style>

<Style TargetType="{x:Type DataGridCell}">
    <Style.Triggers>           
        <Trigger Property="IsSelected" Value="True">
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="BorderBrush" Value="Transparent"/>
            <Setter Property="Foreground" Value="Black"/>
        </Trigger>
    </Style.Triggers>
</Style>

<Style TargetType="{x:Type DataGridRow}">
    <Style.Triggers>
        <Trigger Property="ItemsControl.AlternationIndex" Value="0">
            <Setter Property="Background" Value="#badeee"></Setter>
            <Setter Property="BorderBrush" Value="#badeee"></Setter>
        </Trigger>
        <Trigger Property="ItemsControl.AlternationIndex" Value="1">
            <Setter Property="Background" Value="#92cce5"></Setter>
            <Setter Property="BorderBrush" Value="#92cce5"></Setter>
        </Trigger>
    </Style.Triggers>
</Style>

4
另一种简单的方法是使用IsSelected触发器将选择样式更改为透明。

2
如果其他人也遇到了同样的问题,这篇文章可能会对他们有所帮助。
我们需要禁用DataGrid上的几行,但同时又允许使用箭头键进行导航。因此,我们不得不使用“IsHitTestVisible”来代替控制“IsEnabled”属性。因此,我们无法采用切换到“IsEnable”属性的解决方案。
以下是我最终解决这个问题的方法。我为DataGridRow创建了一个新的附加属性(RowEnable)。可以将此附加属性绑定到视图模型属性以控制“虚拟”启用和禁用。我还为DataGridCell创建了一个新样式,在该样式中,根据相同的视图模型属性将“IsHitTestVisible”设置为false。因此,可以将其视为鼠标/键盘可以看到但无法看到其单元格/列的行。这意味着现在可以基于新的附加属性(RowEnabled)样式化行以显示已禁用/已启用状态。同时,可以查看这些被虚拟禁用的行的工具提示。

0

我需要一个基于代码的解决方案。这个对我有用:

controlGrid.SelectedCellsChanged += (sender, e) =>
    Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Render, new Action(() =>
        controlGrid.UnselectAll()));
controlGrid.Columns.Clear();

由于它有时会闪烁,因此BackgroundProperty也应设置为透明。

Style dataGridCellStyle = new Style(typeof(DataGridCell));
Setter newSetterCell = new Setter(DataGridCell.BackgroundProperty, Brushes.Transparent);
dataGridCellStyle.Setters.Add(newSetterCell);
controlGrid.CellStyle = dataGridCellStyle;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接