В течение дня или двух я пытался выяснить странную ошибку WPF. У меня есть элемент управления ListBox, связанный с ObservableCollection PolicyId, который представляет собой класс, реализующий как INotifyProperty, так и IEquatable, и имеет одно и только одно поле, называемое Id (которое является строкой). PolicyId являются указателями на различные элементы политики, которые изменяют рабочий процесс в других частях программы.ListBox теряет способность изменять selecteditem, когда selecteditem данные изменены
ListBox привязан к коллекции, и есть кнопка добавления и удаления, которая просто добавляет и удаляет идентификаторы в ListBox. Существует также выпадающий ComboBox, который можно использовать для изменения PolicyId выбранного элемента в ListBox на другой идентификатор (какие идентификаторы доступны для выбора, в другом месте). Установка значения свойства ListBox.SelectedItem.Id выполняется в бэкэнд при запуске события ComboBox.SelectionChanged, а значения в ComboBox изменяются при запуске события ListBox.SelectionChanged, что гарантирует, что ни один из элементов в ListBox всегда идентичны.
Теперь эта реализация работает по большей части. Все политики перечислены в ListBox, и вы можете добавить новые (которые добавляют первую доступную ранее выбранную политику в нижней части списка) и выбирать и удалять любую политику, которая вам нравится.
До тех пор, пока вы не заменили одну политику другим, используя comboBox. Как только вы это сделаете, индекс застрял в том, который вы изменили, и нет ничего, что вы можете сделать, чтобы выбрать другую политику (установка ListBox.SelectedIndex не влияет). Нажмите достаточно долго, и в итоге вызывается следующее исключение: «System.ArgumentException: элемент с тем же ключом уже добавлен». Я подозреваю, что ошибка вызвана тем, что WPF пытается добавить выбранный элемент в коллекцию selectedItems listBox, хотя элемент уже существует или что-то в этом роде.
Я знаю, что ошибка имеет какое-то отношение к PolicyId, переопределяющему Equals (да, я вспомнил ограничение, что если Equals говорит, что два объекта равны eachother, то GetHashCode также должен возвращать одинаковое значение для двух, поэтому GetHashCode также переопределяется), потому что подобная настройка используется в других местах программы без проблем. Я не знаю, как все это происходит, тем более, что в коллекции нет дубликатов.
Это ListBox:
<ListBox Name="policyIdList" MinHeight="50" ItemsSource="{Binding Path=DataItem}" IsSynchronizedWithCurrentItem="True" SelectionChanged="policyIdList_SelectionChanged">
<ListBox.Resources>
<Style TargetType="ScrollViewer">
<Setter Property="HorizontalScrollBarVisibility" Value="Hidden" />
</Style>
</ListBox.Resources>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock DataContext="{Binding Path=Id}" Text="{Binding Converter={StaticResource PolicyIdToName}}">
<TextBlock.ToolTip>
<ContentControl Content="{Binding}" ContentTemplate="{StaticResource PolicyByOidListItem}" />
</TextBlock.ToolTip>
</TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
И, хорошие меры, COMBOBOX:
<ComboBox Name="policyIdCombo" Grid.Row="1" Grid.Column="0"
ItemTemplate="{StaticResource PolicyByOidListItem}" SelectionChanged="policyIdCombo_SelectionChanged" />
Когда ваш класс PolicyId переопределяет 'Equals', он также переопределяет' GetHashCode'?Где-то в разделе «Замечания» в [Равно] (http://msdn.microsoft.com/en-us/library/bsc2ak47.aspx): «Типы, которые переопределяют Equals (Object), также должны переопределять GetHashCode, иначе хэш-таблицы могут не быть работать правильно ". Возможно, это как-то источник вашей проблемы, по крайней мере, не стоит также переопределять «GetHashCode». – Clemens
Он делает, так что это не так. Я просто забыл упомянуть, что я также забыл переопределить GetHashCode (я добавил это сейчас). В любом случае, поскольку есть только одно поле, получающее оба этих метода, право действительно тривиально (сравните, если они оба одного класса, сравнивают поле, а затем возвращают поле .GetHashCode() в GetHashCode), если вы знаете GetHashCode должен возвращать тот же хеш для объектов, которые имеют равные знаки как истинные. –