创建了一个简单的WPF窗口,其中包含一个填充了Item类实例的DataGrid。 Datagrid中的项目仅包含10个实例,每个实例重复10次。 在同一窗口中,我放置一个TextBlock,显示在datagrid中选择的项目数。 加载窗口后,选择所有项目,然后清除项目集合(这将产生一组空的选定项目)并重新填充大约5个新实例。此时,不再选择任何项目,因此所选项目的数量应为0,但它为56.
即使略有不同,我怀疑此行为与WPF: SelectedItems with duplicate object references和Datagrid Multiselection of same object有关;我认为这个bug不仅指向DataGrid,而且通常指MultiSelector,但我仍然看不到这个特定问题的简单解决方案。请注意,在我的情况下,我不能用不同的实例替换相同元素的副本,也不能在Items中重新实现Equals或GetHashCode。
在.NET framework 4.0,4.5,4.5.1中执行相同的行为。
以下是重现错误的代码:
档案:
using System.Diagnostics;
namespace WpfApplication2
{
[DebuggerDisplay("{Name}")]
public class Item
{
public string Name
{
get;
set;
}
public string Description
{
get;
set;
}
}
}
窗口(XAML):
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
Loaded="Window_Loaded"
>
<DockPanel LastChildFill="True">
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
<TextBlock Text="Items: " />
<TextBlock Text="{Binding Path=Count}" />
</StackPanel>
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
<TextBlock Text="Selected items: " />
<TextBlock Text="{Binding ElementName=MyDataGrid, Path=SelectedItems.Count}" />
</StackPanel>
<DataGrid IsReadOnly="True" x:Name="MyDataGrid" ItemsSource="{Binding}" AutoGenerateColumns="False" >
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Path=Name}" />
<DataGridTextColumn Binding="{Binding Path=Description}" />
</DataGrid.Columns>
</DataGrid>
</DockPanel>
</Window>
窗口(代码):
using System.Collections.ObjectModel;
using System.Windows;
namespace WpfApplication2
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
ObservableCollection<Item> items = new ObservableCollection<Item>();
PopulateItems(items);
this.DataContext = items;
}
private static void PopulateItems(ObservableCollection<Item> items)
{
for (int i = 0; i < 10; i++)
{
Item item = new Item();
item.Name = string.Format("Name {0}", i);
item.Description = string.Format("Description {0}", i);
for (int j = 0; j < 10; j++)
{
items.Add(item);
}
}
}
private static void ChangeDataSource(ObservableCollection<Item> items)
{
items.Clear();
for (int i = 0; i < 5; i++)
{
Item item = new Item();
item.Name = string.Format("Name {0}", i);
item.Description = string.Format("Description {0}", i);
items.Add(item);
}
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
this.MyDataGrid.SelectAll();
ChangeDataSource(this.DataContext as ObservableCollection<Item>);
}
}
}
答案 0 :(得分:1)
您可以将每个项目的每个副本包装在一个新对象中:
private static void PopulateItems(ObservableCollection<ItemWrapper> wrappers)
{
for (int i = 0; i < 10; i++)
{
Item item = new Item();
item.Name = string.Format("Name {0}", i);
item.Description = string.Format("Description {0}", i);
for (int j = 0; j < 10; j++)
{
var wrapper = new ItemWrapper(item);
wrappers.Add(wrapper);
}
}
}
ItemWrapper
类似于:
public class ItemWrapper
{
public Item { get; set; }
public ItemWrapper(Item item)
{
this.Item = item;
}
}
显然,您应该将XAML更改为:
<DataGrid IsReadOnly="True" x:Name="MyDataGrid" ItemsSource="{Binding}" AutoGenerateColumns="False" >
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Path=Item.Name}" />
<DataGridTextColumn Binding="{Binding Path=Item.Description}" />
</DataGrid.Columns>
</DataGrid>