c# - WPF ListBox & Items with Changing Hashcode -


i have listbox bound collection of items have id used generate result of gethashcode(). when new item added, has id 0 until first saved our database. causing listbox complain; believe reason because when item first used listbox stored in internal dictionary not expect hashcode change.

i can fix removing unsaved item collection (i must notify ui @ stage remove dictionary), save db, , add collection. messy , not have access collection save(businessobject obj) method. have alternative solution problem?

edit in respose blam's answer:

i using mvvm have modified code use bindings. reproduce problem click add, select item, click save, repeat, try make selection. think demonstrates listbox still holding onto old hashcodes in it's internal dictionary, hence conflicting keys error.

<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++;         }     } } 

edit 2 after testing, have discovered few things:

  • changing hash code of item in listbox seems work ok.

  • changing hash code of the selected item in listbox breaks
    it's functionality.

when selection made (single or multiple selection mode) ilist listbox.selecteditems updated. items added selection added selecteditems , items no longer included in selection removed.

if hash code of item changed while selected, there no way remove selecteditems. manuallty calling selecteditems.remove(item), selecteditems.clear() , setting selectedindex -1 have no effect, , item remains in ilist. causes exceptions thrown after next time selected believe once again added selecteditems.

does have alternative solution problem?

hash code of object must not changed during object life-time. shouldn't use mutable data hash code calculation.

update.

i didn't expect, answer cause such discussion. here's detail explanation, may op.

let's @ mutable entity type defined in code, overrides gethashcode and, of course, equals. equality based on id equality:

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 mutable;         if (mutable == null)         {             return false;         }          return this.equals(mutable);     }      public bool equals(mutable other)     {         return id.equals(other.id);     } } 

somewhere in code you've created several instances of type:

        // here's mutable entities hash-code, calculated using mutable data:         var key1 = new mutable { id = 1 };         var key2 = new mutable { id = 2 };         var key3 = new mutable { id = 3 }; 

and external code, uses dictionary<mutable, string> internal purposes:

        // let's use them key dictionary:         var dictionary = new dictionary<mutable, string>         {             { key1, "john" },             { key2, "mary" },             { key3, "peter" }         };          // ok, of keys located properly:         console.writeline(dictionary[key1]);         console.writeline(dictionary[key2]);         console.writeline(dictionary[key3]); 

again, code. suppose, you've changed id of key1. hash-code changed too:

        // let's change hashcode of key1:         key1.id = 4; 

and again, external code. here tries locate data key1:

console.writeline(dictionary[key1]); // ooops! key1 not found in dictionary 

of course, can design mutable types, overrides gethashcode , equals, , calculate hash-code on mutable data. shouldn't that, (except cases, when know, doing).

you can't guarantee, external code won't use dictionary<tkey, tvalue> or hashset<t> internally.


Comments

Popular posts from this blog

c# - Is it possible to remove an existing registration from Autofac container builder? -

asp.net - RadAsyncUpload in code behind, how to? -