ListBox is selecting many items even in SelectionMode=“Single”

拜拜、爱过 提交于 2019-11-30 15:14:07

问题


I have encountered something very strange, simple WPF application

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

with code behind

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 ();
    }
}

and when I click on a single item,

if I continue clicking items, they just aggregate. Clicking an already selected item does nothing. Scratching my head, I have databound lists to ListBoxes before, and have never seen this before. Running Win7 (64), VS2010, behaviour presents with .Net 3.5, .Net 3.5 Client Profile, .Net 4, and .Net 4 Client Profile.

Arg, I should mention I am expecting normal, default, single-select behaviour.


回答1:


Dan Bryant got most of the answer in his comment.

What's going on here is string interning. When you create a bunch of strings with the same value, .Net saves on memory usage by having all references to the same string value actually refer to the same string object. (See this, for instance, for details.)

I don't really know why the ListBox behaves exactly the way it does, which is that the first time you select any item in the list, it selects both that item and the first item in the list. But it doesn't unselect when you click on a new item because checks to see if the SelectedItem is different from the item you just clicked on, and it isn't.

I got exactly the same behavior by binding a ListBox to a collection of test objects:

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;



回答2:


I encountered this problem as well--as others have noted, .NET handles strings in a curious manner to improve memory management.

My immediate workaround was to create a UniqueListItem class to be used in place of the strings I was planning to add to the 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;
    }
}

Because each instance of this object will get its own memory location, adding instances of this object to a listbox control instead of adding strings will result in unique selections, even if the strings displayed in the listbox are identical.

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

I can't say if this is the best solution (that depends on your project's requirements) but hopefully someone finds this helpful.



来源:https://stackoverflow.com/questions/3843784/listbox-is-selecting-many-items-even-in-selectionmode-single

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!