我研究了这个并且很难过:我有一个WPF DataGrid,并使用MVVM模型。在某些情况下,我希望阻止更改DataGrid中的行的能力。我研究了这个,并尝试过像here那样的技术。
在实践中,这是有效的,但是有一个不受欢迎的'闪烁'(它选择点击的行片刻然后回到之前的选择),而这是一个紧密的解决方案我希望有一个更优雅的方式,如首先防止行更改。
我很惊讶没有SelectionChanging或BeforeSelectionChanged所以我可以取消激活事件;并强制防止我的视图模型中的索引更改似乎没有任何区别。
我该怎么做?
谢谢。
答案 0 :(得分:6)
如果您参加previewkeydown
和previewmousedown
活动并在特定情况下致电e.Handled=true
会怎样?
编辑:
满足mvvm风格:
您可以使用Behavior
创建一个DependencyProperty
来绑定您的环境。
在这种行为中,您可以处理事件以及其他一些事情,例如用户点击数据行或标题...
答案 1 :(得分:2)
DispatcherPriority已设置为ContextIdle。这使你有闪烁,因为你的SelectedItem设置了两次(并且它被渲染了两次)。只需将优先级设置为“正常”,您就不会再闪烁了。
答案 2 :(得分:0)
PreviewMouseDown方法here有一些示例。
一般协议是将DataGrid.SelectedItem反转回datagrid的SelectionChanged处理程序内的原始值不能按预期工作;似乎有效的所有代码示例都会通过要求Dispatcher稍后安排它来推迟逆转。</ p>
您的数据网格上有CellStyle吗?对我来说,以下工作:
XAML:
<DataGrid.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="DarkSlateBlue"/>
<Setter Property="Foreground" Value="White"/>
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.CellStyle>
代码隐藏:
private void MyDataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.AddedItems.Count > 0)
{
object x = e.AddedItems[0];
if (x is MyObjectType && x != myViewModel.CurrentItem &&
myViewModel.ShouldNotDeselectCurrentItem())
{
// this will actually revert the SelectedItem correctly, but it won't highlight the correct (old) row.
this.MyDataGrid.SelectedItem = null;
this.MyDataGrid.SelectedItem = myViewModel.CurrentItem;
}
}
}
关键是在SelectionChanged事件之后触发了SelectedCellsChanged事件 - 特别是设置SelectedItem没有正确更新作为只读属性的SelectedCells,因此更多的代码隐藏:
private void MyDataGrid_SelectedCellsChanged(object sender, SelectedCellsChangedEventArgs e)
{
List<DataGridCellInfo> selectedCells = MyDataGrid.SelectedCells.ToList();
List<MyObjectType> wrongObjects = selectedCells.Select(cellInfo => cellInfo.Item as MyObjectType)
.Where (myObject => myObject != myViewModel.CurrentItem).Distinct().ToList();
if (wrongObjects.Count > 0)
{
MyDataGrid.UnselectAllCells();
MyDataGrid.SelectedItem = null;
MyDataGrid.SelectedItem = myViewModel.CurrentItem;
}
}
显然,处理程序需要连接到数据网格上的相应事件。
这可以像预期的那样工作,如果需要,可以正确取消选择更改,并且不会产生闪烁。