WPF:DataGrid禁用选定行样式 - 或行选择

48

我看到很多关于如何在DataGrid中为选定行设置样式的示例,例如这个:

如何在DataGrid中设置选定行的颜色

我能否禁用选定行的样式?我不想覆盖每一个被选定行所改变的东西。只是不想有任何可见的变化。肯定有比创建模板更容易的方法..

或者..

如果更容易的话,禁用选择行..但从浏览这个论坛来看,那也是hacky的

禁用WPF DataGrid中的选择

7个回答

85

我找到了可以去掉选择样式的XAML代码..虽然不是最理想的,但已经足够接近了..

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

1
奇怪的是,它没有禁用所选边框。 - BrainSlugs83
2
这个可以运行,但我认为这一行代码:<Setter Property="Foreground" Value="Black" /> 是不必要的。 - maxp
1
只有在DataGrid的SelectionUnit属性设置为“Cell”时,此代码才有效。 - John Melville
1
完美地工作了。<Setter Property="Foreground" Value="Black" />是必要的。当它被移除时,非焦点单元格中显示的文本会变成白色并消失在白色背景中。 - Galactic
添加SelectionUnit="Cell"后工作正常。 - user3526723
显示剩余2条评论

30

以下方法对我有效:

<DataGrid>
    <DataGrid.CellStyle>
        <Style TargetType="{x:Type DataGridCell}">
            <Style.Triggers>
                <Trigger Property="DataGridCell.IsSelected" Value="True">
                    <Setter Property="BorderBrush">
                        <Setter.Value>
                            <SolidColorBrush Color="Transparent"/>
                        </Setter.Value>
                    </Setter>
                    <Setter Property="Foreground"
                            Value="{DynamicResource
                                   {x:Static SystemColors.ControlTextBrushKey}}"/>
                    <Setter Property="Background">
                        <Setter.Value>
                            <SolidColorBrush Color="Transparent"/>
                        </Setter.Value>
                    </Setter>
                </Trigger>
            </Style.Triggers>
        </Style>
    </DataGrid.CellStyle>
    <!-- ... -->
</DataGrid>

3
这对我也起作用了。被采纳的答案没用。 - The Muffin Man

20

我找到了另一种适用于我情况的方法。我将此样式应用于所有单元格,因为我不希望用户选择任何单元格。

<Style TargetType="{x:Type DataGridCell}">
    <Setter Property="IsHitTestVisible" Value="False"/>
</Style>

11
问题在于这不能帮助键盘导航。 - Mark A. Donohoe
6
请注意,这也会防止用户在单元格中点击链接和按钮。 - dgvid
这正是我想要的。DataGrid对象本身具有“IsHitTestVisible”属性,我将其禁用以获得漂亮的只读网格。 - Daniel
5
这也会禁用列的排序功能。 - sksallaj
但是左上角的单元格(即使在行选择模式下)仍然有黑色边框,你如何禁用它? - BrainSlugs83
显示剩余2条评论

10

我先回答第二个问题:要禁用行的选择,您可以更改DataGrid的RowStyle。

I'll answer the second question first: to disable selection of rows, you could change the RowStyle of your DataGrid.

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

然而,这将更改文本样式,因为该行本身现在处于“禁用”状态。它也不能否认用户仍然可以右键单击行以选择它。如果您真的想禁用与数据网格行的任何交互,您可以执行以下操作:

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

由于行仍然启用,文本的样式不会改变。

现在,如果您只想更改选定行的样式而保留功能不变,可以执行以下操作(基本上与@Dan Stevens的答案相同)。ControlTextBrushKey是系统用于着色文本项的笔刷。有关DynamicResource和StaticResource的解释,请参见此答案

<DataGrid>
    <DataGrid.CellStyle>
        <Style TargetType="{x:Type DataGridCell}">
            <Style.Triggers>
                <Trigger Property="DataGridCell.IsSelected" Value="True">
                    <Setter Property="BorderBrush" Value="Transparent"/>
                    <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
                    <Setter Property="Background" Value="Transparent"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </DataGrid.CellStyle>
    <!--Other DataGrid items-->
</DataGrid>

需要注意的是,上述解决方案不会改变DataGridRowHeader在选中行时的样式,如下图所示(第一行被选中)。

enter image description here


6
这相对来说比较简单:
datagrid.SelectionChanged += (obj, e) =>
  Dispatcher.BeginInvoke(DispatcherPriority.Render, new Action(() =>
    datagrid.UnselectAll()));

这将禁用 DataGrid 上的所有选择。

如果您不想完全禁用选择,而只是隐藏它,则需要修改模板。


1
另外,你的代码似乎对我不起作用。(我出于好奇尝试了一下) - Sonic Soul
1
嗯...如果我错了,请纠正我,但我认为BeginInvoke是Invoke的异步版本,因此肯定会在不同的线程上执行。这里没有回调或线程同步,所以我想那不应该导致多线程问题... - Sonic Soul
2
你错了。调度程序在必要时具有跨线程的能力,但只有在选择与当前线程不同的调度程序时才会这样做。当在 UI 对象中使用时,Dispatcher.Invoke 和 Dispatcher.BeginInvoke 只是简单地执行该方法 - 一个同步执行,另一个异步执行。没有其他线程以任何方式参与其中。很高兴我能为你澄清这一点。我可以理解你为什么对使用 Dispatcher.BeginInvoke 持怀疑态度,因为你误解了它的作用。 - Ray Burns
对我来说不起作用——无论是否使用Dispatcher.Invokieness——它会取消选择行,因此不再是蓝色的,但单元格仍然有一个黑色框,因为选择了它。我可以点击并选择哪个单元格周围有黑框——如何禁用它的那一部分? - BrainSlugs83
此外,为什么需要使用Dispatcher Invoke?难道UI事件不总是在UI线程上触发吗?我在有和没有BeginInvoke / Invoke的情况下都遇到了相同的行为。我很确定这里不需要使用它。 - BrainSlugs83
显示剩余7条评论

1
<Style TargetType="DataGridCell">
    <Style.Triggers>
        <Trigger Property="DataGridCell.IsSelected" Value="True">
            <Setter Property="BorderBrush" Value="Transparent"/> <!--Removes brush color change-->
            <Setter Property="Foreground" Value="{Binding RelativeSource={RelativeSource Mode=Self}, Path=Foreground}"/> <!--Removes foregound change-->
            <Setter Property="Background" Value="Transparent"/>  <!--Removes backgound change-->
        </Trigger>
    </Style.Triggers>
    <Setter Property="FocusVisualStyle" Value="{x:Null}"/> <!--Removes dotted border when on cell selection change made by keyboard-->
</Style>

我稍微修改了Dan StevensJoshuaTheMiller's的解决方案。如果符合以下条件,请使用此解决方案:

  • 你有不同前景色的单元格,应该使用这种方法来保持颜色不变,而不是重置为SystemColors.ControlTextBrushKey
  • 你想禁用鼠标和键盘选择单元格(和行)

1

对于像我这样的人,如果有一些具有不同样式的单元格,又不想覆盖所有样式或为每个样式添加触发器,那么这是一个不错的选择:

<DataGrid.Resources>
    <SolidColorBrush 
        x:Key="{x:Static SystemColors.HighlightBrushKey}" 
        Color="#333333"/>
    <SolidColorBrush 
        x:Key="{x:Static SystemColors.HighlightTextBrushKey}" 
        Color="Black"/>
    <SolidColorBrush 
        x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}" 
        Color="Black"/>
    <SolidColorBrush 
        x:Key="{x:Static SystemColors.InactiveSelectionHighlightTextBrushKey}" 
        Color="Black"/>
</DataGrid.Resources>
HighlightBrushKey 是带有活动选择的突出边框,而 HighlightTextBrushKey 是具有活动选择的文本颜色。
在我的情况下,我希望非活动选择看起来未被选中: InactiveSelectionHighlightBrushKey 是当选择处于非活动状态时的边框,而 InactiveSelectionHighlightTextBrushKey 是当选择处于非活动状态时的文本。
FYI:SystemColors 是 System.Windows.Media 命名空间的静态类。您可以检查它并无耻地覆盖您不喜欢的任何颜色!

有没有一个SystemColor可以覆盖,以全局改变禁用单元格的前景色?谢谢。 - Davide Capodaglio
坦白说,我不知道。你可以在Visual Studio中键入SystemColors,然后按alt+f12查看所有定义的内容,并尝试使用看起来可能是它的颜色进行试错,例如任何带有“inactive”的内容... - Benoit Dufresne

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