首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >WPF ListBox &具有更改哈希代码的项

WPF ListBox &具有更改哈希代码的项
EN

Stack Overflow用户
提问于 2013-05-28 10:08:21
回答 2查看 2K关注 0票数 6

我有一个ListBox绑定到一个具有ID的项集合,该ID用于生成GetHashCode()的结果。添加新项时,它的ID为0,直到首次将其保存到我们的数据库。这导致了我的ListBox的抱怨;我相信原因是当一个项目最初被一个ListBox使用时,它被存储在一个内部Dictionary中,它不会期望hashcode发生变化。

我可以通过从集合中删除未保存的项(我必须在现阶段通知UI以从字典中删除它)、将其保存到DB并将其添加回集合中来解决这个问题。这很麻烦,而且我并不总是可以访问来自我的Save(BusinessObject obj)方法的集合。有谁有解决这个问题的办法吗?

编辑回复Blam的答案:

我使用的是MVVM,所以我修改了代码以使用绑定。若要再现问题,请单击“添加”,选择项目,单击“保存”,“重复”,然后尝试作出选择。我认为这表明ListBox仍然保留着它的内部Dictionary中的旧哈希码,因此出现了键冲突错误。

代码语言:javascript
运行
复制
<Window x:Class="ListBoxHashCode.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">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <StackPanel HorizontalAlignment="Center" Orientation="Horizontal">
            <Button Click="Button_Click_Add" Content="Add"/>
            <Button Click="Button_Click_Save" Content="Save Selected"/>
        </StackPanel>
        <ListBox Grid.Row="1" ItemsSource="{Binding List}" DisplayMemberPath="ID" SelectedItem="{Binding Selected}"/> 
    </Grid>
</Window>

public partial class MainWindow : Window {

    public ObservableCollection<ListItem> List { get; private set; }        
    public ListItem Selected { get; set; }
    private Int32 saveId;

    public MainWindow() {
        this.DataContext = this;            
        this.List = new ObservableCollection<ListItem>();
        this.saveId = 100;
        InitializeComponent();
    }

    private void Button_Click_Add(object sender, RoutedEventArgs e) {
        this.List.Add(new ListItem(0));
    }

    private void Button_Click_Save(object sender, RoutedEventArgs e) {
        if (Selected != null && Selected.ID == 0) {
            Selected.ID = saveId;
            saveId++;
        }
    }
}

在经过一些测试之后,我发现了一些东西:

  • 更改ListBox中项的哈希代码似乎是正常的。
  • 更改ListBox中断中选定项的哈希代码 这是功能。

当选择(单个或多个选择模式)时,IList ListBox.SelectedItems将被更新。添加到选定内容中的项将添加到SelectedItems中,不再包含在所选内容中的项将被移除。

如果项的哈希代码在选定时更改,则无法将其从SelectedItems中删除。即使是手动调用SelectedItems.Remove(item)SelectedItems.Clear()和将SelectedIndex设置为-1也没有任何效果,并且项目仍然保留在IList中。这将在下次选择异常后引发异常,因为我认为它再次添加到SelectedItems中。

EN

Stack Overflow用户

发布于 2013-05-28 15:06:14

我怀疑您的代码的问题在于它没有覆盖Equals

ListBox使用Equals来查找一个条目,所以如果if多个等于返回true,那么它就匹配多个条目,并且简单地搞砸了。

ListBox中的项必须是基于等号的唯一项。

如果您尝试将ListBox绑定到List Int32或List string并重复任何值,那么它也有相同的问题。

你说抱怨的时候。它怎么抱怨的?

在下面这个简单的例子中,ListView并没有因为对GetHashCode的更改而收支平衡。

您实现INotifyPropertyChanged了吗?

代码语言:javascript
运行
复制
<Window x:Class="ListViewGetHashCode.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">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <StackPanel Grid.Row="0" Orientation="Horizontal">
            <Button Click="Button_Click" Content="Button"/>
            <Button Click="Button_Click2" Content="Add"/>
            <Button Grid.Row="0" Click="Button_Click_Save" Content="Save"/>
        </StackPanel>
        <ListBox Grid.Row="1" ItemsSource="{Binding BindingList}" DisplayMemberPath="ID" SelectedItem="{Binding Selected}" VirtualizingStackPanel.VirtualizationMode="Standard"/>
        <!--<ListBox Grid.Row="1" x:Name="lbHash" ItemsSource="{Binding}" DisplayMemberPath="ID"/>--> 
    </Grid>
</Window>

using System.ComponentModel;
using System.Collections.ObjectModel;

namespace ListViewGetHashCode
{
    public partial class MainWindow : Window
    {
        ObservableCollection<ListItem> li = new ObservableCollection<ListItem>();
        private Int32 saveId = 100;
        private Int32 tempId = -1;
        public MainWindow()
        {
            this.DataContext = this;
            for (Int32 i = 1; i < saveId; i++) li.Add(new ListItem(i));

            InitializeComponent();

        }
        public ObservableCollection<ListItem> BindingList { get { return li; } }
        public ListItem Selected { get; set; }
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Int32 counter = 0;
            foreach (ListItem l in li)
            {
                l.ID = -l.ID;
                counter++;
                if (counter > 100) break;
            }
        }
        private void Button_Click2(object sender, RoutedEventArgs e)
        {          
            //li.Add(new ListItem(0)); // this is where it breaks as items were not unique
            li.Add(new ListItem(tempId));
            tempId--;
        }   
        private void Button_Click_Save(object sender, RoutedEventArgs e)
        {
            if (Selected != null && Selected.ID <= 0)
            {
                Selected.ID = saveId;
                saveId++;
            }
        }
    }
    public class ListItem : Object, INotifyPropertyChanged
    {
        private Int32 id;
        public event PropertyChangedEventHandler PropertyChanged;
        protected void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }  
        public Int32 ID 
        {
            get 
            { 
                return (id < 0) ? 0 : id;
                //if you want users to see 0 and not the temp id 
                //internally much use id
                //return id;
            }
            set
            {
                if (id == value) return;
                id = value;
                NotifyPropertyChanged("ID");
            }
        }
        public override bool Equals(object obj)
        {
            if (obj is ListItem)
            {
                ListItem comp = (ListItem)obj;
                return (comp.id == this.id);
            }
            else return false;
        }
        public bool Equals(ListItem comp)
        {
            return (comp.id == this.id);
        }
        public override int GetHashCode()
        {
            System.Diagnostics.Debug.WriteLine("GetHashCode " + id.ToString());
            return id;
            //can even return 0 as the hash for negative but it will only slow 
            //things downs
            //if (id > 0) return id;
            //else return 0;
        }
        public ListItem(Int32 ID) { id = ID; }
    }
}
票数 1
EN
查看全部 2 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16789360

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档