9

我对此进行了研究并感到困惑:我有一个 WPF DataGrid,并使用了 MVVM 模型。在某些情况下,我想阻止更改 DataGrid 中的行的能力。我对此进行了研究,并尝试了类似此处发现的技术。

在实践中,这是可行的,但是有一个不受欢迎的“闪烁”(它选择单击的行一会儿然后返回到先前的选择),虽然这是一个接近的解决方案,但我希望有一种更优雅的方法,例如防止一开始就完全改变了行。

我很惊讶没有 SelectionChanging 或 BeforeSelectionChanged,所以我可以取消触发事件;并强行阻止我的视图模型中的索引更改似乎没有任何区别。

我怎样才能做到这一点?

谢谢你。

4

3 回答 3

6

如果你在特定情况下接受previewkeydownpreviewmousedown事件并调用会发生什么?e.Handled=true

编辑:满足 mvvm 风格:你可以创建一个BehaviorDependencyProperty可以绑定你的环境。在这种行为中,您可以处理事件以及其他一些事情,例如用户是否单击数据行或标题...

于 2011-07-26T05:45:55.133 回答
2

DispatcherPriority 已设置为 ContextIdle。这使您闪烁,因为您的 SelectedItem 设置了两次(并且它已被渲染两次)。只需将优先级设置为正常,您将不再闪烁。

于 2012-01-11T09:55:16.340 回答
0

PreviewMouseDown 方法在这里有一些示例。

普遍的共识是,将 DataGrid.SelectedItem 反转回其在数据网格的 SelectionChanged 处理程序中的原始值不会按预期工作;所有似乎有效的代码示例都通过要求 Dispatcher 稍后安排它来推迟反转。

您的数据网格上有 CellStyle 吗?对我来说,以下工作:

xml:

<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; 
        }
    }
}

关键是 SelectedCellsChanged 事件在 SelectionChanged 事件之后触发 - 特别是,设置 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;
    }
}

显然,处理程序需要连接到数据网格上的相应事件。

这像预期的那样工作,如果需要,可以正确取消选择更改,并且不会产生闪烁。

于 2013-09-24T04:55:06.183 回答