单击 WPF DatagridRow Border

问题描述

我根据 DataGrid、DataGridRow 和 DataGridCell 的样式集设计了一个 Datagrid。我已经使用 DatagridRow 样式和 DGR_Border(如代码中所示)在行之间设置了边框。当我单击一行时,它会被选中,但是当我单击行边框时,没有选择任何行,单击这些边框时没有任何反应。我想单击行并选择它,而不会因为我不小心在行之间单击而强迫我重新单击。由于这些边框是 DatagridRow 本身的一部分,它们与某些行相关联并且必须响应点击或点击?我最终在 Datagrid 上实现了一个 MouseDown 事件,并将依赖对象的父对象标识为 DatagridRow 并获取和设置索引。这对于单选模式非常有效,但如果使用 Keybaord 修饰符 Control 和 Shift 单击鼠标,我最终将实现扩展案例的逻辑。我觉得 XAML 中隐藏了一些简单的东西,可以设置它来解决这个问题。希望有人的眼睛能看到我所缺少的东西。请在下面找到具有确切问题的示例:

MainWindow.xaml

<Window x:Class="WpfApp3.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Title="MainWindow" Height="450" Width="800"
    x:Name="this" >
<Window.Resources>
    <ResourceDictionary>
        <Style x:Key="DataGridStyle" targettype="DataGrid">
            <Setter Property="Background" Value="DarkGray"/>
            <Setter Property="Foreground" Value="Blue"/>
            <Setter Property="BorderBrush" Value="{x:Null}"/>
            <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="CanUserResizeColumns" Value="False"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate targettype="DataGrid">
                        <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="True">
                            <ScrollViewer x:Name="DG_ScrollViewer" PanningMode="Both" >
                                <ScrollViewer.Template>
                                    <ControlTemplate targettype="ScrollViewer">
                                        <Grid>
                                            <Grid.ColumnDeFinitions>
                                                <ColumnDeFinition Width="Auto" />
                                                <ColumnDeFinition Width="*"/>
                                                <ColumnDeFinition Width="Auto" />
                                            </Grid.ColumnDeFinitions>
                                            <Grid.RowDeFinitions>
                                                <RowDeFinition Height="Auto"/>
                                                <RowDeFinition Height="*"/>
                                                <RowDeFinition Height="Auto"/>
                                            </Grid.RowDeFinitions>
                                            <DataGridColumnHeadersPresenter x:Name="PART_ColumnHeadersPresenter" Grid.Column="1" Visibility="{Binding HeadersVisibility,ConverterParameter={x:Static DataGridHeadersVisibility.Column},Converter={x:Static DataGrid.HeadersVisibilityConverter},RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
                                            <ScrollContentPresenter x:Name="PART_ScrollContentPresenter" 
                                                            CanContentScroll="{TemplateBinding CanContentScroll}" 
                                                            Grid.ColumnSpan="2" Grid.Row="1"/>
                                            <ScrollBar x:Name="PART_VerticalScrollBar"
                                        Grid.Row="1" Grid.Column="2" 
                                        MinWidth="40"
                                        Value="{TemplateBinding VerticalOffset}"
                                        Maximum="{TemplateBinding ScrollableHeight}"
                                        ViewportSize="{TemplateBinding ViewportHeight}"
                                        Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"
                                        Panel.ZIndex="5"
                                        ClipToBounds="False"/>

                                            <ScrollBar x:Name="PART_HorizontalScrollBar"
                                        Orientation="Horizontal"
                                        Grid.Row="2"
                                        Grid.Column="1"
                                        Value="{TemplateBinding HorizontalOffset}"
                                        Maximum="{TemplateBinding ScrollableWidth}"
                                        ViewportSize="{TemplateBinding ViewportWidth}"
                                        Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"/>
                                        </Grid>
                                    </ControlTemplate>
                                </ScrollViewer.Template>
                                <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                            </ScrollViewer>
                        </Border>

                        <ControlTemplate.Triggers>
                            <Trigger Property="VerticalScrollBarVisibility" Value="Hidden">
                                <Setter TargetName="DG_ScrollViewer" Property="VerticalScrollBarVisibility" Value="Hidden"/>
                            </Trigger>
                            <Trigger Property="VerticalScrollBarVisibility" Value="disabled">
                                <Setter TargetName="DG_ScrollViewer" Property="VerticalScrollBarVisibility" Value="disabled"/>
                            </Trigger>
                            <Trigger Property="HorizontalScrollBarVisibility" Value="Hidden">
                                <Setter TargetName="DG_ScrollViewer" Property="HorizontalScrollBarVisibility" Value="Hidden"/>
                            </Trigger>
                            <Trigger Property="HorizontalScrollBarVisibility" Value="disabled">
                                <Setter TargetName="DG_ScrollViewer" Property="HorizontalScrollBarVisibility" Value="disabled"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
            <Setter Property="GridLinesVisibility" Value="None"/>
            <Setter Property="ColumnWidth" Value="*"/>
            <Setter Property="IsReadOnly" Value="True"/>
            <Setter Property="HorizontalScrollBarVisibility" Value="disabled"/>
            <Style.Triggers>
                <MultiTrigger>
                    <MultiTrigger.Conditions>
                        <Condition Property="IsGrouping" Value="true"/>
                        <Condition Property="VirtualizingPanel.IsVirtualizingWhenGrouping" Value="false"/>
                    </MultiTrigger.Conditions>
                    <Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
                </MultiTrigger>
            </Style.Triggers>
        </Style>

        <Style x:Key="DataGridRowStyle" targettype="{x:Type DataGridRow}">
            <Setter Property="SnapsToDevicePixels" Value="true"/>
            <Setter Property="Validation.ErrorTemplate" Value="{x:Null}"/>
            <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
            <Setter Property="ValidationErrorTemplate">
                <Setter.Value>
                    <ControlTemplate>
                        <TextBlock Foreground="Red" Margin="2,0" Text="!" VerticalAlignment="Center"/>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate targettype="{x:Type DataGridRow}">

                        <!--BorderBrush="{Binding RelativeSource={RelativeSource TemplatedParent},Path=Tag,Converter={StaticResource RandomColorBrushGeneratorConverter}}"-->
                        <Border x:Name="DGR_Border"
                        IsHitTestVisible="True"
                        BorderThickness="0,3,3" 
                        BorderBrush="Black" 
                        Background="{TemplateBinding Background}" 
                        SnapsToDevicePixels="True" 
                        CornerRadius="4,4,4" 
                        Opacity="1" 
                        RenderTransformOrigin="0.5,0.5">
                            <Border.RenderTransform>
                                <TransformGroup>
                                    <ScaleTransform/>
                                    <SkewTransform/>
                                    <RotateTransform/>
                                    <TranslateTransform/>
                                </TransformGroup>
                            </Border.RenderTransform>
                            <SelectiveScrollingGrid>
                                <SelectiveScrollingGrid.ColumnDeFinitions>
                                    <ColumnDeFinition Width="Auto"/>
                                    <ColumnDeFinition Width="*"/>
                                </SelectiveScrollingGrid.ColumnDeFinitions>
                                <SelectiveScrollingGrid.RowDeFinitions>
                                    <RowDeFinition Height="*"/>
                                    <RowDeFinition Height="Auto"/>
                                </SelectiveScrollingGrid.RowDeFinitions>

                                <DataGridCellsPresenter Grid.Column="1" ItemsPanel="{TemplateBinding ItemsPanel}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                                <DataGridDetailsPresenter Grid.Column="1" Grid.Row="1" SelectiveScrollingGrid.SelectiveScrollingOrientation="{Binding AreRowDetailsFrozen,ConverterParameter={x:Static SelectiveScrollingOrientation.Vertical},Converter={x:Static DataGrid.RowDetailsScrollingConverter},RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" Visibility="{TemplateBinding DetailsVisibility}"/>
                            </SelectiveScrollingGrid>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
            <Setter Property="Margin" Value="0,0"/>
            <Setter Property="Background" Value="Gray"/>
            <Setter Property="Opacity" Value="1"/>
            <Style.Triggers>
                <Trigger Property="IsNewItem" Value="True">
                    <Setter Property="Margin" Value="{Binding NewItemmargin,RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
                </Trigger>
                <Trigger Property="IsSelected" Value="True">
                    <Setter Property="Background" Value="Red"/>
                </Trigger>
            </Style.Triggers>
        </Style>

        <Style x:Key="DataGridCellStyle" targettype="{x:Type DataGridCell}">
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="BorderBrush" Value="Transparent"/>
            <Setter Property="BorderThickness" Value="0"/>
            <Setter Property="FontSize" Value="16"/>
            <Setter Property="Padding" Value="12"/>
            <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate targettype="{x:Type DataGridCell}">
                        <Border
                    IsHitTestVisible="True"
                    BorderBrush="{TemplateBinding BorderBrush}" 
                    BorderThickness="{TemplateBinding BorderThickness}" 
                    Background="{TemplateBinding Background}" 
                    SnapsToDevicePixels="True">
                            <Grid Background="Transparent" IsHitTestVisible="True">
                                <ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                                          Margin="{TemplateBinding Padding}"/>
                            </Grid>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
            <Setter Property="Foreground" Value="LightGray"/>

            <Style.Triggers>
                <Trigger Property="IsSelected" Value="True">
                    <Setter Property="Foreground" Value="Black"/>
                </Trigger>
                <Trigger Property="IsEnabled" Value="false">
                    <Setter Property="Foreground" Value="{StaticResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </ResourceDictionary>
</Window.Resources>
<Grid>
    <DataGrid 
        x:Name="_mainDataGrid"
        ItemsSource="{Binding ElementName=this,Path=Dummies}"
        Style="{StaticResource DataGridStyle}"
        CellStyle="{StaticResource DataGridCellStyle}"
        RowStyle="{StaticResource DataGridRowStyle}"
        SelectionMode="Extended"
        PreviewMouseDown="DataGrid_PreviewMouseDown"/>
</Grid>

MainWindow.xaml.cs

using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace WpfApp3
{
    public class Dummy
    {
        public Dummy(string f,string l,string a)
        {
            FirstName = f;
            LastName = l;
            Address = a;
        }
        public string FirstName { get; set; }
        public string LastName { get; set; }

        public string Address { get; set; }
    }
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            Dummies = new ObservableCollection<Dummy>();
            for(int i = 0; i < 10; i++)
            {
                Dummy dummy = new Dummy("F" + i.ToString(),"L" + i.ToString(),"ADDRESS: " + i.ToString());
                Dummies.Add(dummy);
            }
            InitializeComponent();
        }

        public ObservableCollection<Dummy> Dummies { get; }

        public static T GetParentOfType<T>(DependencyObject current)
          where T : DependencyObject
        {
            for (DependencyObject parent = VisualTreeHelper.GetParent(current);
                parent != null;
                parent = VisualTreeHelper.GetParent(parent))
            {
                if (parent is T result)
                    return result;
            }

            return null;
        }

        /// <summary>
        /// Want to Avoid this and have something in XAML 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DataGrid_PreviewMouseDown(object sender,System.Windows.Input.MouseButtonEventArgs e)
        {
            //Will end up implementing logic for Multiselection using Control and shift modifiers
            if (e.OriginalSource is DependencyObject dep &&
                GetParentOfType<DataGridRow>(dep) is DataGridRow dataGridRow)
            {
                _mainDataGrid.Selectedindex = dataGridRow.GetIndex();
            }
        }
    }
}

注意::我已经尝试了此处提到的解决方DataGrid row selection not working when padding is added to cells,如我上面的代码所示,但没有帮助。

解决方法

由于我找不到直接的方法,所以我做了其他事情来修复它。在 DataGridRow 样式中,我将边框设置为透明,并在行选择时启用它,并为 DataGridCell 样式中的每个单元格绘制底部边框,复制 DataGrid 行边框并在行选择时禁用它。

DataGridRow 样式更改:

    <Border x:Name="DGR_Border"
                                 IsHitTestVisible="True"
                                 BorderThickness="0" 
                                 BorderBrush="Transparent" 
                                 Background="{TemplateBinding Background}" 
                                 SnapsToDevicePixels="True" 
                                 CornerRadius="4,4,4" 
                                 Opacity="1" 
                                 RenderTransformOrigin="0.5,0.5">
    
 <ControlTemplate.Triggers>
    
                                 <Trigger Property="IsSelected" Value="True">
                                     <Setter TargetName="DGR_Border" Property="BorderThickness" Value="0,6"/>
                                     <Setter TargetName="DGR_Border" Property="BorderBrush" Value="Black"/>
                                 </Trigger>
                             </ControlTemplate.Triggers>

DataGridCell 样式更改:

    <Style x:Key="DataGridCellStyle" TargetType="{x:Type DataGridCell}">
                 <Setter Property="Background" Value="Transparent"/>
                 <Setter Property="BorderBrush" Value="Black"/>
                 <Setter Property="BorderThickness" Value="0,6"/>
                 <Setter Property="FontSize" Value="16"/>
                 <Setter Property="Padding" Value="12"/>
                 <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
    
 <Style.Triggers>
                     <Trigger Property="IsSelected" Value="True">
                         <Setter Property="Foreground" Value="Black"/>
                         <Setter Property="BorderThickness" Value="0"/>
                         <Setter Property="BorderBrush" Value="Transparent"/>
                     </Trigger>
                 </Style.Triggers>