Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# DataGrid无法取消选择已修改的项_C#_.net_Wpf_.net Core - Fatal编程技术网

C# DataGrid无法取消选择已修改的项

C# DataGrid无法取消选择已修改的项,c#,.net,wpf,.net-core,C#,.net,Wpf,.net Core,我有一个带有DataGrid的WPF应用程序。 此DataGrid绑定到包含一组模型的ObservableCollection。 此DataGrid的选择模式设置为“扩展” 如果当前选择了某个项目,然后收到更新(例如,所选项目的某些内容在刷新期间发生更改),然后用户尝试选择另一个项目,则不会取消选择上一个项目 OnselectionChanged将激发,但不包含上一项,并且似乎无法取消选择它 运行此程序的代码(使用.net core 3.1清理wpf应用程序) DataGrid(如您所见)也不存

我有一个带有DataGrid的WPF应用程序。 此DataGrid绑定到包含一组模型的ObservableCollection。 此DataGrid的选择模式设置为“扩展”

如果当前选择了某个项目,然后收到更新(例如,所选项目的某些内容在刷新期间发生更改),然后用户尝试选择另一个项目,则不会取消选择上一个项目

OnselectionChanged将激发,但不包含上一项,并且似乎无法取消选择它

运行此程序的代码(使用.net core 3.1清理wpf应用程序)

DataGrid(如您所见)也不存储任何选定项

            <DataGrid Grid.Row="1"
                  x:Name="ItemsDataGrid"
                  SelectionMode="Extended"
                  ItemsSource="{Binding Items}">
            <DataGrid.Resources>
                <Style TargetType="{x:Type DataGridCell}">
                    <Style.Triggers>
                        <Trigger Property="DataGridCell.IsSelected" Value="True">
                            <Setter Property="Background" Value="Red" />
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </DataGrid.Resources>
        </DataGrid>
根据请求,这里是将项目添加到列表框的代码

private void Button_Click(object sender, RoutedEventArgs e)
    {
        SelectedItemsListBox.Items.Clear();

        foreach(var item in ItemsDataGrid.SelectedItems)
        {
            SelectedItemsListBox.Items.Add(item);
        }

        SelectedItemsListBox.Items.Refresh();
    }
在这里,应用程序刚刚打开,单击“刷新”按钮显示3项

这里选择了第一个项目,单击了修改维度的“更改项目”按钮,还请注意此项目现在如何显示其下面的描述,这是一个列表框,显示所有当前选择的项目,并在单击“显示所选项目”后刷新(包括列表框.clear)

在这里,第三个项目已被单击并选中,反过来也应取消选中以前选中的项目,但如列表框所示,它仍然处于选中状态


我已经把这个问题缩减到了这一点,结果不是我的选择方法,不是我使用的多选择器,也不是我使用的UI框架,这个简单的解决方案仍然存在一个问题,让我不知所措,不知道它可能是什么。

您观察到的行为与您的
GetHashCode
实现有关

从您发布的类定义(在Pastebin上)中,我了解到您的数据项正在实现
IEquatable
,并且在此上下文中还重写
object.GetHashCode

您的实现基于可变字段计算哈希代码
这通常应该避免,因为它可能导致意外的行为(比如你现在正在经历的)

“通常,对于可变引用类型,只有在以下情况下,才应重写GetHashCode():

  • 您可以从不可变的字段计算哈希代码;或者
  • 可以确保可变对象包含在依赖于的集合中时,其哈希代码不会更改 它的散列码。”
(Microsoft文档:)

可变字段的问题在于,当对象在基于哈希的集合中使用时,它们可能会更改。
如果用于哈希代码计算的字段发生更改,则哈希代码也将发生更改,因此原始哈希键的存储值将丢失

现在您必须知道,
DataGrid
Selector
通常使用哈希表来存储所选项目,以提高查找性能。由于您的类型实现了
IEquatable
DataGrid
试图使用
GetHashCode
返回的值作为键,因为它假定一个重写的实现。
GetHashCode
的这种实现在使用前由
DataGrid
检查可靠性,但显然这种可靠性检查没有考虑用于计算的字段的可变性。当然,这需要反思。避免反射并在连续调用后测试
GetHashCode
的结果是否为常量似乎是很合理的

考虑到这一点,我们现在可以解释这种行为:

  • 项目被选中并存储在“选定项目”哈希表中
  • DataGrid
    使用项本身作为基于哈希的选定项备份集合的键,以提高查找速度
  • 由于项实现了
    IEquatable
    ,哈希表愉快地调用所选项上的
    GetHashCode
    ,以获取对象哈希作为值(所选项)的键
  • 现在,您可以通过编辑
    DataGrid
    的一个单元格来修改该项,这也会导致计算出的哈希代码发生意外的更改
  • 接下来,选择一个不同的项目。
    DataGrid
    现在尝试从selected items集合中删除以前选择的项。但由于项目的哈希代码已更改,因此查找不会返回任何项目。因此,旧的和取消选择的项目仍保留在“选定项目”集合中
解决方案是遵循指导原则,避免覆盖
对象.GetHashCode
,因为在您的情况下:

  • 无法从不可变(只读)字段和
  • 当可变对象包含在依赖其哈希代码的集合中时,无法确保该对象的哈希代码不会更改
因此,删除/修复
GetHashCode
覆盖将解决此问题


实施改进 添加类型为
ObservableCollection
SelectedItems
集合作为
列表框的绑定源,并添加
数据网格。SelectionChanged
事件处理程序:

查看模型

private ObservableCollection<Window> _items = new ObservableCollection<Window>();
public ObservableCollection<Window> Items
{
    get => _items;
    set => SetProperty(ref _items, value);
 }

private ObservableCollection<Window> _selectedItems = new ObservableCollection<Window>();
public ObservableCollection<Window> SelectedItems
{
    get => _selectedItems ;
    set => SetProperty(ref _selectedItems, value);
}
private observetecollection\u items=new observetecollection();
公共可观测收集项目
{
获取=>\u项;
set=>SetProperty(参考项,值);
}
私有ObservableCollection _selectedItems=新ObservableCollection();
公共可观测集合SelectedItems
{
get=>\u selectedItems;
set=>SetProperty(ref\u selectedItems,value);
}
查看(代码隐藏)

DataGridSelectionChanged上的私有void(对象发送者,SelectionChangedEventArgs e)
{
var viewModel=this.DataContext作为viewModel;
foreach(e.AddedIte中的窗口addedItem
private void Button_Click(object sender, RoutedEventArgs e)
    {
        SelectedItemsListBox.Items.Clear();

        foreach(var item in ItemsDataGrid.SelectedItems)
        {
            SelectedItemsListBox.Items.Add(item);
        }

        SelectedItemsListBox.Items.Refresh();
    }
private ObservableCollection<Window> _items = new ObservableCollection<Window>();
public ObservableCollection<Window> Items
{
    get => _items;
    set => SetProperty(ref _items, value);
 }

private ObservableCollection<Window> _selectedItems = new ObservableCollection<Window>();
public ObservableCollection<Window> SelectedItems
{
    get => _selectedItems ;
    set => SetProperty(ref _selectedItems, value);
}
private void OnDataGridSelectionChanged(object sender, SelectionChangedEventArgs e)
{
  var viewModel = this.DataContext as ViewModel;
  foreach (Window addedItem in e.AddedItems.Cast<Window>())
  {
    viewModel.SelectedItems.Add(addedItem);
  }
  foreach (Window removedItem in e.RemovedItems.Cast<Window>())
  {
    viewModel.SelectedItems.Remove(removedItem);
  }
}
<DataGrid SelectionMode="Extended"
          SelectionChanged="OnDataGridSelectionChanged">
   ...
</DataGrid>

<ListBox ItemsSource="{Binding SelectedItems}" />
    <DataGrid Grid.Row="1"
              x:Name="ItemsDataGrid"
              SelectionMode="Extended"
              ItemsSource="{Binding ItemsCollection}">
        <DataGrid.ItemContainerStyle>
            <Style TargetType="DataGridRow">
                <Style.Triggers>
                    <Trigger Property="IsSelected" Value="True">
                        <Setter Property="Background" Value="Red" />
                    </Trigger>
                </Style.Triggers>
            </Style>
        </DataGrid.ItemContainerStyle>
    </DataGrid>
    <ListBox Grid.Row="2" ItemsSource="{Binding SelectedItems, ElementName=ItemsDataGrid}"/>