在FullRow选择模式下禁用DataGrid当前单元格边框

66
我正在使用 DataGrid 进行行选择模式(即 SelectionUnit="FullRow")。我只想要移除用户在突出显示一行时当前单元格周围的边框,以便实现真正的完整行选择(而不是单元格级别的选择)。 我不介意网格保留当前单元格的概念,我只想通过更改当前单元格的样式来删除那个麻烦的当前单元格边框。 最简单的方法是什么?

我曾经认为我想要这样做(并且避免Tab / Shift-Tab键移动到下一个/上一个单元格,就像Mark A. Donohoe在2015年6月4日10:34的第二部分A所述),但是我后来意识到,当水平滚动启用并在DataGrid上活动时,我仍然希望右/左箭头键移动到下一个/上一个单元格,并且在这样做时,我仍然需要当前单元格的边框。Donohoe的A简化/修复了非第一列上的“IsTabStop”= false(同时仍允许通过单击任何列而不仅仅是第一列进行行选择以及通过向下/向上键使用键盘进行下一个/上一个行移动)。 - Tom
7个回答

117
您可以将 DataGridCellBorderThickness 属性设置为 0。
<DataGrid ...
          SelectionUnit="FullRow">
    <DataGrid.CellStyle>
        <Style TargetType="DataGridCell">
            <Setter Property="BorderThickness" Value="0"/>
            <!-- Update from comments.
                 Remove the focus indication for the selected cell -->
            <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
        </Style>
    </DataGrid.CellStyle>
    <!-- ... -->
</DataGrid>

2
如果用户使用箭头键,这种方法就不起作用了。在单元格中仍然会出现虚线选择边框。 - Michael Yanni
18
@Michael Yanni:您在谈论“FocusVisualStyle”。要禁用它,请在“CellStyle”中将其设置为null,如<Setter Property="FocusVisualStyle" Value="{x:Null}"/> - Fredrik Hedblad
如何在边框设置为0的情况下恢复单元格的缺失间距? - ygoe
1
@LonelyPixel,不要将线条粗细设置为零,而是将边框画刷设置为透明。 - Mark A. Donohoe
4
这实际上并没有阻止那些单元格获取焦点,只是你看不到而已。因此,当焦点循环遍历单元格而不是行时,Tab键似乎无法正常工作。我已经添加了一个解答来解决这个问题。 - Mark A. Donohoe

15

在这里看到了另一个接近答案的回答,但它没有去掉焦点矩形。以下是如何消除所有边框的方法。

<DataGrid.Resources>
    <Style TargetType="{x:Type DataGridCell}">
        <Setter Property="BorderThickness" Value="0" />
        <Setter Property="FocusVisualStyle" Value="{x:Null}" />
    </Style>
</DataGrid.Resources>

另外,由于从技术上讲这些单元格仍然会获得焦点(只是你看不到它),为了使标签键前进到下一行而不是下一个单元格,我基于上面的样式定义了一个单元格样式,并添加以下内容...

<DataGrid.Resources>
    <Style x:Key="NoFocusDataGridCell" TargetType="{x:Type DataGridCell}" BasedOn="{StaticResource {x:Type DataGridCell}}">
        <Setter Property="Focusable"        Value="False" />
        <Setter Property="IsTabStop"        Value="False" />
        <Setter Property="IsHitTestVisible" Value="False" />
    </Style>
</DataGrid.Resources>

...然后我将其应用于除第一列定义之外的所有列。这样,制表键将前进到下一行,而不是下一个单元格。

然而,回到边框问题。如果您希望隐藏它们但仍希望它们作为间距布局的一部分,请将以上内容更改为以下内容...

<DataGrid.Resources>
    <Style TargetType="{x:Type DataGridCell}">
        <Setter Property="BorderBrush" Value="Transparent" />
        <Setter Property="FocusVisualStyle" Value="{x:Null}" />
    </Style>
</DataGrid.Resources>

享受吧!:)


这更接近了,但仍有一个警告:如果您单击列0,则会获得活动选择高亮刷(如预期),但是单击列1及以上的列,您会收到非活动选择高亮刷(意外)。非活动刷子会保持不变(单击其他行)直到您单击列0。然后,活动刷子会保持不变,直到DataGrid失去焦点。 - Olson.dev
1
有趣。我之前没有看到过,但现在我一定会尝试。然而,我添加它的原因是为了修复选项卡顺序。也许解决方法就是将其从focusable = false更改为istabstop = false。这应该可以达到同样的效果。 - Mark A. Donohoe
1
我刚刚尝试了 IsTabStop="False" 的调整,它似乎覆盖了所有情况。从技术上讲,当您单击时,非第一列单元格会接收焦点,并且您可以使用箭头左/右键将焦点更改为其他单元格,但是按制表符键会转到下一行的第一个单元格或下一个控件(如果聚焦于最后一行的单元格之一)。然而,我怀疑这不是问题。也许对于屏幕阅读器来说呢?无论如何,谢谢! - Olson.dev
1
我曾经认为我想要OP想要的(并且避免Tab / Shift-Tab键移动到下一个/上一个单元格,就像Mark A. Donohoe在2015年6月4日10:34所说的第二部分一样),但是我后来意识到,当启用并激活DataGrid上的水平滚动条时,我仍然希望右/左箭头键移动到下一个/上一个单元格,并且在这样做时,我仍然需要当前单元格的边框。Donohoe的A简化/修复了非第一列上的“IsTabStop”= false(同时仍允许通过单击任何列而不仅仅是第一列进行行选择,并通过向下/向上键通过键盘移动到下一个/上一个行)。 - Tom

6
<Style x:Key="DataGrid" TargetType="DataGrid">
    <Setter Property="CellStyle">
        <Setter.Value>
            <Style TargetType="DataGridCell">
                <Setter Property="BorderThickness" Value="0"/>
                <Setter Property="Foreground" Value="{Binding Foreground, RelativeSource={RelativeSource TemplatedParent}}" />
                <Setter Property="Background" Value="{Binding Background, RelativeSource={RelativeSource TemplatedParent}}" />
            </Style>
        </Setter.Value>
    </Setter>
</Style>

添加这两行代码有助于保持ResourceDictionary应用的样式,感谢@marius。 - Rachel

2
真正的答案是:
<!-- put it in your cell style -->
<DataTrigger Binding="{Binding SelectionUnit, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" Value="FullRow">
    <Setter Property="BorderThickness" Value="0" />
</DataTrigger>

这个问题是关于仅在FullRow选择模式下禁用它,但其他答案提供了完全禁用它甚至在单元格选择模式下的解决方案。

回答一个非常古老的问题,但不管你信不信,WPF和WinForms现在仍然被使用。


1
如果您不想处理XAML样式,可以尝试这个简单的hack。它不像XAML样式那样好用,但您可以尝试一下,看看是否适合您。对于简单的单击单元格而言很好用,但如果您尝试拖动单元格,它将不会在此之后删除焦点(虽然我相信您可以添加另一个检查该问题的情况)。
private void YourDataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    YourDataGrid.Focus();
}

PS:不要忘记将事件处理程序添加到您的 DataGridSelectionChanged 属性中。


0
如果你正在使用 xceedDataGridControl,那么将 NavigationBehavior 设置为 RowOnly
<xcdg:DataGridControl NavigationBehavior="RowOnly" SelectionMode="Single"  ....

0
如果您想在单元格可编辑且被选中时仅显示边框,可以重写DataGridCell模板并添加一个多触发器,用于当单元格IsSelected且不是IsReadOnly时。然后,如果您为列或DataGrid设置了IsReadOnly = true,则不会显示单元格的边框。
<ControlTemplate x:Key="MellowDataGridCellTemplate" TargetType="{x:Type DataGridCell}">
    <Grid>
        <ContentPresenter VerticalAlignment="Center" />
        <Rectangle Name="FocusVisual" Stroke="White" StrokeThickness="1" Fill="Transparent" HorizontalAlignment="Stretch" 
                           VerticalAlignment="Stretch" IsHitTestVisible="false" Opacity="0" />

    </Grid>
    <ControlTemplate.Triggers>
        <MultiTrigger>
            <MultiTrigger.Conditions>
                <Condition Property="IsReadOnly" Value="False" />
                <Condition Property="IsSelected" Value="True" />
            </MultiTrigger.Conditions>
            <Setter TargetName="FocusVisual" Property="Opacity" Value="1"/>
        </MultiTrigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

在样式中使用模板

<Style TargetType="{x:Type DataGridCell}" x:Key="MellowGridDataGridCell">
    <Setter Property="Template" Value="{StaticResource MellowDataGridCellTemplate}" />
</Style>

并使用样式

<DataGrid CellStyle={StaticResource MellowGridDataGridCell >
    ...
</DataGrid>

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