Datagrid SelectedItems错误地处理相同对象引用的副本

时间:2015-06-05 07:46:26

标签: c# .net wpf datagrid

创建了一个简单的WPF窗口,其中包含一个填充了Item类实例的DataGrid。 Datagrid中的项目仅包含10个实例,每个实例重复10次。 在同一窗口中,我放置一个TextBlock,显示在datagrid中选择的项目数。 加载窗口后,选择所有项目,然后清除项目集合(这将产生一组空的选定项目)并重新填充大约5个新实例。此时,不再选择任何项目,因此所选项目的数量应为0,但它为56.

即使略有不同,我怀疑此行为与WPF: SelectedItems with duplicate object referencesDatagrid 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>);
            }
        }
    }

1 个答案:

答案 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>