即使在SelectionMode =“Single”中,ListBox也会选择很多项目

时间:2010-10-02 00:06:29

标签: wpf .net-4.0 listbox binding

我遇到了一些非常奇怪,简单的WPF应用程序

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

代码隐藏

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

当我点击一个项目时,

Why multiple values selected?

如果我继续点击项目,他们只会聚合。单击已选择的项目不执行任何操作。抓我的头,我之前有数据包列表给ListBoxes,之前从未见过这个。运行Win7(64),VS2010,行为呈现.Net 3.5,.Net 3.5 Client Profile,.Net 4和.Net 4 Client Profile。

Arg,我应该提到我期待正常的,默认的,单选行为。

2 个答案:

答案 0 :(得分:11)

丹·布莱恩特在评论中得到了大部分答案。

这里发生的是字符串实习。当您创建一组具有相同值的字符串时,.Net通过对相同字符串值的所有引用实际引用相同的字符串对象来节省内存使用量。 (例如,请参阅this了解详细信息。)

我真的不知道为什么ListBox的行为与它完全一样,这是第一次选择列表中的任何项目时,它会同时选择该项目和列表中的第一项。但是,当您单击新项目时,它不会取消选择,因为检查SelectedItem是否与您刚刚单击的项目不同,但事实并非如此。

通过将ListBox绑定到测试对象的集合,我得到了完全相同的行为:

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

MainWindow.xaml

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

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;

答案 1 :(得分:7)

我也遇到了这个问题 - 正如其他人所说,.NET以奇怪的方式处理字符串以改善内存管理。

我的直接解决方法是创建一个UniqueListItem类来代替我计划添加到列表框的字符串。

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

因为此对象的每个实例都将获得自己的内存位置,所以将此对象的实例添加到列表框控件而不是添加字符串将导致唯一的选择,即使列表框中显示的字符串相同也是如此。

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

我不能说这是否是最佳解决方案(取决于您项目的要求),但希望有人认为这有帮助。