2013-03-12 16 views
5

Per un giorno o due ho cercato di capire uno strano bug WPF. Ho un controllo con un ListBox che è associato a una ObservableCollection di PolicyId, che è una classe implementa sia INotifyProperty che IEquatable e ha un solo campo, chiamato Id (che è una stringa). I PolicyId sono puntatori a vari elementi policicy che modificano il flusso di lavoro in altre parti del programma.ListBox perde la possibilità di modificare selecteditem quando selecteditem data è modificato

Il ListBox è associato alla raccolta e vi è un pulsante Aggiungi e Rimuovi che aggiunge e rimuove semplicemente ID al ListBox. C'è anche un ComboBox a discesa che può essere usato per cambiare il PolicyId dell'elemento selezionato nel ListBox con un altro Id (quali Id sono disponibili per la selezione viene modificato altrove). L'impostazione del valore della proprietà ListBox.SelectedItem.Id viene eseguita nel backend quando viene attivato l'evento ComboBox.SelectionChanged e i valori nel ComboBox vengono modificati quando viene attivato l'evento ListBox.SelectionChanged, per garantire che nessuno degli elementi in i ListBox sono sempre identici.

Ora, questa implementazione funziona per la maggior parte. Tutte le politiche sono elencate nel ListBox e puoi aggiungerne di nuove (che aggiungono la prima politica disponibile non selezionata in precedenza nella parte inferiore dell'elenco) e selezionare e rimuovere qualsiasi politica che ti piace.

Finché non è stata sostituita una politica con un'altra utilizzando la comboBox, ovvero. Una volta che l'indice si blocca su quello che hai cambiato e non c'è nulla che puoi fare per selezionare un'altra politica (l'impostazione di ListBox.SelectedIndex non ha alcun effetto). Fare clic in giro abbastanza a lungo e alla fine viene generata la seguente eccezione: "System.ArgumentException: un elemento con la stessa chiave è già stato aggiunto." Sospetto che l'errore sia causato da WPF che tenta di aggiungere l'elemento selezionato alla raccolta "selectedItems" di listBox anche se l'elemento è già presente o qualcosa del genere.

So che il bug ha qualcosa a che fare con PolicyId che esegue l'override di Equals (sì, ho ricordato il vincolo che se Equals dice che due oggetti sono uguali tra loro allora anche GetHashCode dovrebbe restituire lo stesso valore per entrambi, quindi GetHashCode è anche sovrascritto) perché una configurazione simile viene utilizzata altrove nel programma senza problemi. Non so come faccia a rovinare tutto, soprattutto perché non ci sono mai duplicati nella collezione.

Questa è la 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> 

E, per buona misura, il comboBox:

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

Quando la classe PolicyId esegue l'override di 'Equals', esegue anche l'override di' GetHashCode'?Da qualche parte nella sezione Note di [Equals] (http://msdn.microsoft.com/en-us/library/bsc2ak47.aspx): "I tipi che sovrascrivono Equals (Object) devono anche sovrascrivere GetHashCode, altrimenti le tabelle hash potrebbero non funziona correttamente ". Forse questa è in qualche modo la fonte del tuo problema, almeno non è sbagliato anche sovrascrivere 'GetHashCode'. – Clemens

+0

Lo fa, quindi non è così. Ho semplicemente dimenticato di dire che mi sono ricordato di sovrascrivere anche GetHashCode (l'ho aggiunto ora). Ad ogni modo, dato che c'è solo un campo che ottiene entrambi i metodi giusti è davvero banale (confrontare se sono entrambi della stessa classe, confrontare il campo, quindi restituire il campo.GetHashCode() in GetHashCode), purché tu conosca GetHashCode dovrebbe restituire lo stesso hash per gli oggetti che Ugals contrassegna come veri. –

risposta

9

Credo che il problema è che si sta Changning codice hash della voce quando si cambia è ID, e il ListBox non si aspetta questo. See here per ulteriori informazioni.

Ho appena aggiornato un'applicazione da .NET 3.5 a 4.0 e ho riscontrato questo problema. Se, come me, non si riesce a utilizzare un codice hash fissa poi una soluzione è:

  1. rimuovere l'oggetto da modificare dalla lista
  2. Notifica l'interfaccia utente del cambiamento
  3. modificare l'ID del tuo oggetto (con conseguente modifica del codice hash)
  4. Aggiungi il tuo oggetto all'elenco e notifica l'interfaccia utente della modifica.
+0

Grazie, questo è anche il modo in cui alla fine (inconsciamente) l'abbiamo risolto - dal momento che il passaggio degli elementi non ha funzionato, è stato consentito solo aggiungere e rimuovere le politiche. La casella combinata è stata utilizzata per selezionare quale politica aggiungere. –

Problemi correlati