我在 WPF 页面上有一个
DataGrid
,并且想要阻止用户选择单元格。由于此功能仅用于测试,因此我不想更改代码中的所有内容。
填充完我的
DataGrid
后,我确保选择了它的所有行。现在我想确保用户无法选择/取消选择行。
我尝试设置
IsEnabled = false
和 IsHitTestVisible = "False"
但这两种解决方案都会禁用滚动条。
有什么办法可以做到这一点吗?
为什么不只为您的
IsHitTestVisible="False"
或 DataGridRow
对象设置 DataGridCell
呢?
在
<DataGrid.Resources>
中使用隐式样式很容易做到这一点,并且应该只禁用行或单元格上的命中测试,这应该保留DataGrid
功能的其他区域,例如标题或滚动条
<DataGrid.Resources>
<Style TargetType="{x:Type DataGridRow}">
<Setter Property="IsHitTestVisible" Value="False" />
</Style>
</DataGrid.Resources>
为了能够阻止用户更改DataGrid的选择并且不限制单元格中控件的交互性,可以使用以下解决方案:
将 PreviewMouseDown 添加到 XAML 中的 DataGrid:
<DataGrid PreviewMouseDown="DataGrid_DisableSelection">
并在cs中定义DataGrid_DisableSelection:
private void DataGrid_DisableSelection(object sender, MouseButtonEventArgs e)
{
e.Handled = true;
}
你有两个选择:
您禁用样式中的选择(在这种情况下,您仅关闭样式中的颜色,但物理上的 SelectedItem 或 SelectedItems 将会改变)。您可以轻松了解如何关闭选择样式。
您可以在不更改 SelectedItem 或 SelectedItems 的情况下禁用更改选择(在这种情况下,您的选择样式也不会更改)。
在 WPF 中,我不喜欢覆盖标准控件。所以,我们需要一个
Behavior
:
public class DisableSelectionDataGridBehavior : Behavior<DataGrid>
{
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.PreviewMouseLeftButtonDown += AssociatedObjectOnPreviewMouseLeftButtonDown;
}
private void AssociatedObjectOnPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
var dependencyObject = AssociatedObject.InputHitTest(e.GetPosition(AssociatedObject)) as DependencyObject;
if (dependencyObject == null) return;
var elements = dependencyObject.GetParents().OfType<FrameworkElement>().Where(DataGridCellExtended.GetIsDisableSelection).ToList();
if (!elements.Any()) return;
e.Handled = true;
var args = new MouseButtonEventArgs(e.MouseDevice, e.Timestamp, e.ChangedButton, e.StylusDevice);
args.RoutedEvent = UIElement.MouseLeftButtonDownEvent;
args.Source = e.Source;
elements.ForEach(item =>
{
item.RaiseEvent(args);
var children = item.GetChildren<FrameworkElement>();
children.ForEach(child => child.RaiseEvent(args));
});
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.PreviewMouseLeftButtonDown -= AssociatedObjectOnPreviewMouseLeftButtonDown;
}
}
其次,你需要一个
Extended
课程:
public class DataGridCellExtended
{
public static readonly DependencyProperty IsDisableSelectionProperty = DependencyProperty.RegisterAttached("IsDisableSelection", typeof(Boolean), typeof(DataGridCellExtended));
public static Boolean GetIsDisableSelection(DependencyObject o)
{
return (Boolean)o.GetValue(IsDisableSelectionProperty);
}
public static void SetIsDisableSelection(DependencyObject o, Boolean value)
{
o.SetValue(IsDisableSelectionProperty, value);
}
}
最后在 XAML 中你需要这样的东西:
<DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="{x:Type items:YourViewModel}">
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<Button Margin="0"
extends:DataGridCellExtended.IsDisableSelection="True">
<Path Data="M5,0L3,2 1,0 0,1 2,3 0,5 1,6 3,4 5,6 6,5 4,3 6,1z"
Fill="{Binding Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType=DataGridCell}}"
Width="12"
Height="12"
Stretch="Uniform"/>
</Button>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
您可以为扩展课程编写逻辑。
public static IEnumerable<DependencyObject> GetParents(this DependencyObject element)
{
if (element != null)
{
while (true)
{
var parent = element.GetParent();
var dependencyObject = parent;
element = parent;
if (dependencyObject == null)
{
break;
}
yield return element;
}
yield break;
}
else
{
throw new ArgumentNullException("element");
}
}
private static IEnumerable<DependencyObject> GetChildrenRecursive(this DependencyObject element)
{
if (element != null)
{
for (var i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++)
{
var dependencyObject = VisualTreeHelper.GetChild(element, i);
yield return dependencyObject;
foreach (var childrenRecursive in dependencyObject.GetChildrenRecursive())
{
yield return childrenRecursive;
}
}
}
else
{
throw new ArgumentNullException("element");
}
}