Search code examples
c#wpfbindingequalsgethashcode

Overriding GetHash code and Equals break bindings


Currently i have the problem, that when i override GetHashCode and Equals, my binding get's broken.

This are my models:

class A
{
    private string name;

    public string Name
    {
        get { return name; }
        set { name = value; /*Some notification stuff*/ }
    }

    public override bool Equals(object obj)
    {
        if (obj == null)
        {
            return false;
        }
        else if (obj is A)
        {
            return (obj as A).Name == this.name;
        }
        else
        {
            return false;
        }
    }

    public override int GetHashCode()
    {
        if (name != null)
        {
            return name.GetHashCode();
        }
        else
        {
            return 0;
        }
    }

}

class B
{
    private ObservableCollection<A> items;
    private A selectedItem;

    public ObservableCollection<A> Items
    {
        get { return items; }
        set { items = value; /*Some notification stuff*/ }
    }

    public A SelectedItem
    {
        get { return selectedItem; }
        set { selectedItem = value; /*Some notification stuff*/ }
    }
}

The xaml is the following:

<Label Grid.Row="0" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center" Content="A:" />
<TextBox Grid.Row="0" Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Center" Height="24"
                             Text="{Binding SelectedItem.Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, diagnostics:PresentationTraceSources.TraceLevel=High}" />


<Label Grid.Row="1" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Top" Content="List" />
<ListBox Grid.Row="1" Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
                             ItemsSource="{Binding Items, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" SelectedItem="{Binding SelectedItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, diagnostics:PresentationTraceSources.TraceLevel=High,
                        ValidatesOnDataErrors=True}" DisplayMemberPath="Name" />

The problem is, if i override GetHashCode and Equals the binding only working the first time selecting an item and changing the name. After that it seems broken. I've added some binding debugging but this returns no errors or detaching/deactivation.

If i remove the overridings, every think works fine.

Am i doing some thing wrong here?


Solution

  • Your solution is acceptable.

    Consider either making A a sealed class or checking whether this.GetType() == obj.GetType() (in the case where obj is not null, of course). If this is more derived than obj, or if obj is more derived than this, you should return false.

    Never keep the base class behavior of GetHashCode when you have overridden Equals.

    As Andy Korneyev said in his answer, be aware that a mutable object where Equals (and hence also GetHashCode) can change after the instance was added to a Hashtable, Dictionary<,>, HashSet<> etc. can be dangerous. If the object is mutated while a hash table holds a reference to it, that hash table will be screwed up, and the object might be impossible to locate on O(1) lookups in that hash table.