问题描述
我根据 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>