Cod*_*095 5 c# wpf listbox mvvm
我有一个ListBox项目集合,它们具有用于生成结果的ID GetHashCode().添加新项目时,它的ID为0,直到它首次保存到我们的数据库中.这导致我ListBox抱怨; 我相信原因是因为当一个项目首次被ListBox它使用时,它存储在一个Dictionary不希望哈希码改变的内部.
我可以通过从集合中删除未保存的项来解决这个问题(我必须在此阶段通知UI将其从字典中删除),保存到数据库,然后将其添加回集合中.这很麻烦,我并不总是可以从我的Save(BusinessObject obj)方法访问该集合.有没有人有这个问题的替代解决方案?
编辑在回应Blam的回答:
我正在使用MVVM,所以我修改了代码以使用绑定.要重现问题,请单击"添加",选择项目,单击"保存","重复",然后尝试进行选择.我认为这表明它ListBox仍然保留在其内部的旧哈希码中Dictionary,因此冲突的键错误.
<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++;
}
}
}
Run Code Online (Sandbox Code Playgroud)
编辑2经过一些测试,我发现了一些东西:
更改一个项目的哈希码ListBox似乎工作正常.
改变的哈希码所选择的项目在ListBox中断
它的功能.
当进行选择(单个或多个选择模式)时,IList ListBox.SelectedItems更新.添加到选择中的项目将被添加到,SelectedItems并且将删除选择中不再包含的项目.
如果项目的哈希码在选中时更改,则无法将其从中删除SelectedItems.即使是手动调用SelectedItems.Remove(item),SelectedItems.Clear()并且设置SelectedIndex为-1都没有效果,并且该项目仍保留在IList.这会导致在下次选择异常后抛出异常,因为我相信它会再次添加SelectedItems.
有人有解决这个问题的替代方案吗?
对象的哈希码在对象的生命周期内不得更改。您不应使用可变数据进行哈希码计算。
更新。
没想到我的回答会引起这么大的讨论。这里有一些详细的解释,可能会对OP有所帮助。
让我们看一下代码中定义的一些可变实体类型,它会GetHashCode覆盖Equals. 平等是建立在Id平等的基础上的:
class Mutable : IEquatable<Mutable>
{
public int Id { get; set; }
public override int GetHashCode()
{
return Id.GetHashCode();
}
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
var mutable = obj as Mutable;
if (mutable == null)
{
return false;
}
return this.Equals(mutable);
}
public bool Equals(Mutable other)
{
return Id.Equals(other.Id);
}
}
Run Code Online (Sandbox Code Playgroud)
您在代码中的某个位置创建了此类型的多个实例:
// here's some mutable entities with hash-code, calculated using mutable data:
var key1 = new Mutable { Id = 1 };
var key2 = new Mutable { Id = 2 };
var key3 = new Mutable { Id = 3 };
Run Code Online (Sandbox Code Playgroud)
这是一些外部代码,用于Dictionary<Mutable, string>其内部目的:
// let's use them as a key for the dictionary:
var dictionary = new Dictionary<Mutable, string>
{
{ key1, "John" },
{ key2, "Mary" },
{ key3, "Peter" }
};
// everything is ok, all of the keys are located properly:
Console.WriteLine(dictionary[key1]);
Console.WriteLine(dictionary[key2]);
Console.WriteLine(dictionary[key3]);
Run Code Online (Sandbox Code Playgroud)
再说一次,你的代码。假设,你已经改变Id了key1。哈希码也发生了变化:
// let's change the hashcode of key1:
key1.Id = 4;
Run Code Online (Sandbox Code Playgroud)
再次,外部代码。在这里,它尝试通过以下方式查找一些数据key1:
Console.WriteLine(dictionary[key1]); // ooops! key1 was not found in dictionary
Run Code Online (Sandbox Code Playgroud)
当然,您可以设计可变类型,它会覆盖GetHashCode和Equals,并计算可变数据的哈希码。但你真的不应该这样做(除非你明确知道你在做什么)。
您不能保证任何外部代码都不会Dictionary<TKey, TValue>在HashSet<T>内部使用。
| 归档时间: |
|
| 查看次数: |
1544 次 |
| 最近记录: |