阻止用户在 WPF DataGrid 中选择/取消选择行
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16217582/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Stopping user from selecting/unselecting rows in WPF DataGrid
提问by mans
I have a DataGridon a WPF page and want to prevent the user from selecting cells. As this feature is needed just for testing, I don't want to change everything in code.
我DataGrid在 WPF 页面上有一个,并希望阻止用户选择单元格。由于此功能仅用于测试,因此我不想更改代码中的所有内容。
After my DataGridis filled, I make sure all of its rows are selected. Now I want to make sure that user cannot select/unselect rows.
DataGrid填满my 后,我确保它的所有行都被选中。现在我想确保用户无法选择/取消选择行。
I tried setting IsEnabled = falseand IsHitTestVisible = "False"but both of these solutions disable scrollbars.
我尝试设置IsEnabled = false,IsHitTestVisible = "False"但是这两种解决方案都禁用了滚动条。
Is there any way to do this?
有没有办法做到这一点?
回答by Rachel
Why not just set IsHitTestVisible="False"for your DataGridRowor DataGridCellobjects only?
为什么不只IsHitTestVisible="False"为您的DataGridRow或DataGridCell对象设置?
That's easy to do using an implicit style in the <DataGrid.Resources>, and should only disable hit-testing on the rows or cells, which should leave the other areas of the DataGridfunctional, such as the Headers or ScrollBars
在 中使用隐式样式很容易做到<DataGrid.Resources>,并且应该只禁用行或单元格上的命中测试,这应该保留功能的其他区域DataGrid,例如标题或滚动条
<DataGrid.Resources>
<Style TargetType="{x:Type DataGridRow}">
<Setter Property="IsHitTestVisible" Value="False" />
</Style>
</DataGrid.Resources>
回答by Smagin Alexey
You have two choices:
你有两个选择:
You disable selection in style (in this case you turn off only color in style, but physically SelectedItem or SelectedItems will change). You can easily find out how you can turn off selection style.
You can disable changing selection without changing SelectedItem or SelectedItems (in this case your selection style will not change too).
您禁用样式中的选择(在这种情况下,您仅关闭样式中的颜色,但物理 SelectedItem 或 SelectedItems 将更改)。您可以轻松了解如何关闭选择样式。
您可以在不更改 SelectedItem 或 SelectedItems 的情况下禁用更改选择(在这种情况下,您的选择样式也不会更改)。
In WPF i don't like to override standard controls. So, we need a Behavior:
在 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;
}
}
Second, you need an Extendedclass:
其次,你需要一个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);
}
}
And finally in XAML you need something like this:
最后在 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>
You can write your logic for extended class.
您可以为扩展类编写逻辑。
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");
}
}

