我基于Datagrid、DataGridRow和DataGridCell的样式集设计了一个Datagrid。我已经使用DatagridRow样式和DGR_border设置了行之间的边界(如代码中所示(。当我单击一行时,它会被选中,但当我单击行边界时,没有选择任何行,当单击这些边界时不会发生任何事情。我想单击行并选择它,而不会因为我不小心在行之间单击而强迫我重新单击。由于这些边界是DatagridRow本身的一部分,所以它们与某一行相关联,并且必须响应点击或点击测试?我最终在Datagrid上实现了一个MouseDown事件,并将依赖对象的父对象标识为DatagridRow,并获取和设置索引。这将完美地适用于单选模式,但如果鼠标单击Keybaord修饰符Control和Shift,我最终将实现Extended case的逻辑。我觉得XAML中隐藏着一些简单的东西,可以设置它来解决这个问题。希望有人能看到我所缺少的东西。请在下面找到确切问题的样本:
主窗口.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,0,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,0,3"
BorderBrush="Black"
Background="{TemplateBinding Background}"
SnapsToDevicePixels="True"
CornerRadius="4,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,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>
主窗口.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行选择不起作用,如我上面的代码所示,但它没有帮助。
由于我找不到一个直接的方法,我做了一些其他的事情来解决它。在DataGridRow样式中,我将我的边框设置为透明的,并在行选择时启用它,并在DataGridCell样式中为每个单元格绘制下边框,该样式复制了DataGrid行边框,并在列选择时禁用它。
DataGridRow样式更改:
<Border x:Name="DGR_Border"
IsHitTestVisible="True"
BorderThickness="0"
BorderBrush="Transparent"
Background="{TemplateBinding Background}"
SnapsToDevicePixels="True"
CornerRadius="4,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,0,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,0,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>