ListBox выбирает много элементов, даже в SelectionMode = "Single" - PullRequest
7 голосов
/ 02 октября 2010

Я столкнулся с чем-то очень странным, простым приложением 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 ]

11 голосов
/ 02 октября 2010

Дэн Брайант получил большую часть ответа в своем комментарии.

Здесь происходит интернирование строк.Когда вы создаете набор строк с одинаковым значением, .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;
7 голосов
/ 10 февраля 2011

Я также столкнулся с этой проблемой - как уже отмечали другие, .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;
    }
}

Поскольку каждый экземпляр этого объекта будет иметь свою собственную область памяти, добавление экземпляров этого объекта в элемент управления listbox вместо добавления строк приведет к уникальным выборкам, даже если строки, отображаемые в списке, являютсяидентичны.

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

Я не могу сказать, является ли это лучшим решением (зависит от требований вашего проекта), но, надеюсь, кто-то найдет это полезным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...