2010-10-02 2 views
7

ho incontrato qualcosa di molto strano, semplice applicazione WPFListBox sta selezionando molti articoli anche in SelectionMode = "single"

<Window x:Class="ListBoxSelection.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> 
     <ListBox ItemsSource="{Binding Path=Strings}" SelectionMode="Single"/> 
    </Grid> 
</Window> 

con codice dietro

public class ViewModel 
{ 
    public List<string> Strings { get; set; } 

    public ViewModel() 
    { 
     Strings = new List<string>(); 
     Strings.Add ("A"); 
     // add many items ... 
     Strings.Add ("A"); 
    } 
} 

/// <summary> 
/// Interaction logic for MainWindow.xaml 
/// </summary> 
public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 

     DataContext = new ViewModel(); 
    } 
} 

e quando clicco su un singolo elemento ,

Why multiple values selected?

se continuo gli elementi cliccando, t ehi solo aggregati. Fare clic su un elemento già selezionato non fa nulla. Grattandomi la testa, ho elenchi di databound per ListBoxes prima, e non ho mai visto questo prima. L'esecuzione di Win7 (64), VS2010, presenta il comportamento con .Net 3.5, .Net 3.5 Client Profile, .Net 4 e .Net 4 Client Profile.

Arg, dovrei dire che mi aspetto un comportamento normale, predefinito, a selezione singola.

+4

Sospetto che ciò stia accadendo perché tutte le selezioni sono in realtà la stessa istanza (tutti gli stessi riferimenti alla stessa stringa costante). –

+0

Controllare la proprietà SelectedItems.Forse sta selezionando solo un oggetto, ma qualcosa negli stili è rovinato. –

+0

@Dan. Questa è una teoria interessante, la testerei anch'io, ma devo partire presto. –

risposta

11

Dan Bryant ha ottenuto la maggior parte della risposta nel suo commento.

Quello che sta succedendo qui è lo interning delle stringhe. Quando crei un gruppo di stringhe con lo stesso valore, .Net salva l'utilizzo della memoria perché tutti i riferimenti allo stesso valore di stringa si riferiscono effettivamente allo stesso oggetto stringa. (Vedere this, ad esempio, per i dettagli.)

Non so davvero perché il ListBox si comporta esattamente come fa, ovvero che la prima volta che si seleziona un elemento nell'elenco, seleziona sia quell'elemento e il primo elemento nell'elenco. Ma non deseleziona quando fai clic su un nuovo elemento perché controlla se lo SelectedItem è diverso dall'elemento su cui hai appena fatto clic e non lo è.

Ho ottenuto esattamente lo stesso comportamento legandosi un ListBox a una collezione di oggetti di test:

public class TestObject 
{ 
    public override string ToString() 
    { 
     return GetHashCode().ToString(); 
    } 
} 

In MainWindow.xaml:

<ListBox x:Name="MyListBox" ItemsSource={Binding}"/> 

In MainWindow.xaml.cs:

ObservableCollection<TestObject> test = new ObservableCollection<TestObject>(); 
TestObject t = new TestObject(); 
test.Add(t); 
test.Add(t); 
test.Add(t); 
test.Add(t); 
test.Add(t); 
test.Add(t); 
MyListBox.DataContext = test; 
+0

accettato per rispondere ai commenti di Dan e aggiungerne altri. si scusa Dan, anche se i miei complimenti per essere stato il primo sulla scena. mi piacerebbe sapere perché ListBox si comporta in questo modo quando si incontra questo specifico scenario ... –

+2

@johnny g, penso che questo sia un artefatto della filosofia di design dietro WPF, ovvero che una casella di elenco rappresenti un elenco di elementi di dati distinti. Solitamente non si vincolano le stringhe direttamente, ma piuttosto gli elementi di dati che vengono visualizzati come stringhe (tramite DataTemplate o DisplayMember), il che significa che si dovrebbero avere elementi di dati univoci, anche se le stringhe renderizzate sono identiche in alcuni casi. Se è necessario selezionare elementi con rappresentazioni identiche, è necessario disporre di alcuni oggetti dati che codifichino il modo in cui sono diversi (devono essere diversi o non si avranno due opzioni) –

+2

Se gli elementi non univoci erano un caso d'uso previsto, 'SelectedItem' non sarebbe una proprietà ragionevole da esporre. –

7

ho incontrato anche questo problema - come altri hanno notato, .NET gestisce le stringhe in un curioso m per migliorare la gestione della memoria.

La mia soluzione immediata consisteva nel creare una classe UniqueListItem da utilizzare al posto delle stringhe che stavo progettando di aggiungere alla listbox.

class UniqueListItemObject 
{ 
    private string _text; 
    public string Text { get { return _text; } set { _text = value; } } 

    public UniqueListItemObject(string input) 
    { 
     Text = input; 
    } 
    public UniqueListItemObject() 
    { 
     Text = string.Empty; 
    } 

    public override string ToString() 
    { 
     return Text; 
    } 
} 

Poiché ogni istanza di questo oggetto otterrà la propria posizione di memoria, l'aggiunta di istanze di questo oggetto a un controllo casella di riepilogo invece di aggiungere stringhe si tradurrà in selezioni uniche, anche se le stringhe mostrate nella casella di riepilogo sono identici.

 yourListBox.Items.Add(new UniqueListItemObject(yourStringHere); 

non posso dire se questa è la soluzione migliore (che dipende dai requisiti del vostro progetto), ma si spera che qualcuno trova questo utile.

+0

Come ottengo i dati dal listBox dopo averlo aggiunto? Mi aiuti per favore. –