2013-03-12 11 views
5

Na dzień lub dwa próbowałem znaleźć dziwny błąd WPF. Mam kontrolę z ListBox, który jest związany z ObservableCollection z PolicyId, który jest klasy implementacji zarówno INotifyProperty i IEquatable i ma jedno i tylko jedno pole, o nazwie Id (co jest ciągiem znaków). PolicyId są wskaźnikami różnych elementów polityki, które modyfikują przepływ pracy w innych częściach programu.ListBox traci możliwość zmiany selecteditem po modyfikacji danych selecteditem

ListBox jest związany z kolekcją, a istnieje przycisk dodawania i usuwania, który po prostu dodaje i usuwa Id do ListBox. Istnieje także rozwijany ComboBox, który może być użyty do zmiany ID PolicyId wybranego elementu w Liście ListBox na inny Identyfikator (to, które Id są dostępne do selekcji, jest modyfikowany gdzie indziej). Ustawianie wartości właściwości ListBox.SelectedItem.Id odbywa się w backendach po wywołaniu zdarzenia ComboBox.SelectionChanged, a wartości w polu ComboBox zostają zmienione po wywołaniu zdarzenia ListBox.SelectionChanged, aby upewnić się, że żadne z elementów w ListBox są zawsze identyczne.

Teraz ta implementacja działa w przeważającej części. Wszystkie zasady są wymienione w ListBoxie i możesz dodać nowe (które dodaje pierwszą dostępną, nie wybraną wcześniej zasadę na dole listy) i wybrać i usunąć dowolną polisę.

Tak długo, jak nie wymieniono jednej polityki na inną za pomocą comboBox, to znaczy. Gdy to zrobisz, indeks utknie w tym, który zmieniłeś i nie ma nic, co możesz zrobić, aby wybrać inną politykę (ustawienie ListBox.SelectedIndex nie ma żadnego efektu). Kliknij wystarczająco długo i ostatecznie zostanie zgłoszony następujący wyjątek: "System.ArgumentException: Element z tym samym kluczem został już dodany." Podejrzewam, że błąd jest spowodowany przez WPF próbujący dodać wybrany element do kolekcji "selectedItems" listbox, mimo że element już tam jest lub coś w tym stylu.

Wiem, że błąd ma coś wspólnego z PolicyId przesłaniem Equali (tak, przypomniałem sobie ograniczenie, że jeśli Equals mówi, że dwa obiekty są sobie równe, to GetHashCode powinien również zwrócić tę samą wartość dla dwóch, więc GetHashCode jest również przesłonięte), ponieważ podobna konfiguracja jest używana w innych miejscach programu bez problemów. Nie wiem, jak to wszystko wprawia w zakłopotanie, zwłaszcza że w kolekcji nie ma żadnych duplikatów.

To 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> 

I dobrych środków, ComboBox:

<ComboBox Name="policyIdCombo" Grid.Row="1" Grid.Column="0" 
ItemTemplate="{StaticResource PolicyByOidListItem}" SelectionChanged="policyIdCombo_SelectionChanged" /> 
+0

Kiedy klasa PolicyId przesłania słowo "równa się", czy zastępuje również kod "GetHashCode"?Gdzieś w sekcji Uwagi [Równe] (http://msdn.microsoft.com/en-us/library/bsc2ak47.aspx): "Typy, które przesłaniają Równości (Obiekt), muszą także nadpisywać Kod GetHashCode, w przeciwnym razie tabele mieszania mogą nie działa poprawnie ". Być może jest to w jakiś sposób źródło problemu, przynajmniej nie jest źle, aby przesłonić 'GetHashCode'. – Clemens

+0

To robi, więc to nie to. Po prostu zapomniałem wspomnieć, że pamiętałem, aby zastąpić również GetHashCode (dodałem to teraz). W każdym razie, ponieważ istnieje tylko jedno pole uzyskiwania obu tych metod, jest to naprawdę banalne (porównaj, czy obie są tej samej klasy, porównaj pole, a następnie zwróć pole.GetHashCode() w GetHashCode), o ile znasz GetHashCode powinien zwrócić ten sam skrót dla obiektów, które mają równe znaczniki jako prawdziwe. –

Odpowiedz

9

Myślę, że problemem jest to, że są Changning hashcode elementu, gdy zmieni to ID, i ListBox nie spodziewa się tego. See here, aby uzyskać więcej informacji.

Właśnie zaktualizowałem aplikację z .NET 3.5 do 4.0 i napotkałem ten problem. Jeśli tak jak ja jesteś w stanie użyć stałego hashcode następnie obejście jest:

  1. usunąć obiekt należy zmienić z listy
  2. Informuj UI zmiany
  3. zmienić ID swoje obiekt (powodujący zmianę jego kodu)
  4. Dodaj swój obiekt z powrotem do listy i powiadom interfejs użytkownika o zmianie.
+0

Dzięki, to jest przypadkowo, jak ostatecznie (nieświadomie) rozwiązaliśmy to - ponieważ przełączanie elementów nie działało, dopuszczaliśmy tylko dodawanie i usuwanie zasad. Pole kombi służyło do wyboru zasad do dodania. –

Powiązane problemy