Элементы в ListBox отображаются как имя класса

Проблема в следующем: я связал ListBox со списком элементов какого-то пользовательского класса (List<Person> persons = new List<Person>()) с помощью свойства DataSource. Конечно, ValueMember и DisplayMember присваиваются соответствующим свойствам этого класса. Когда я впервые загружаю данные, все выглядит нормально. Однако, когда я нажимаю на какой-либо элемент (т.е. 7-ю позицию, считая от 1), а затем перестраиваю список И количество элементов МЕНЬШЕ 7, в результате я не вижу правильных текстов в списке. Вместо этого каждый элемент отображается как имя класса, которому предшествует пространство имен.

Другими словами, вместо списка:

  • Джон Доу
  • Джейн Доу
  • Кто-нибудь еще

Я вижу это:

  • MyNamespace.Person
  • MyNamespace.Person
  • MyNamespace.Person

Похоже, это зависит от последнего SelectedIndex. Если элемента с таким индексом больше нет (элементов меньше), возникает проблема.

Пробовал разные комбинации переназначения ValueMember и DisplayMember, а так же присваивать null свойству DataSource списка и переназначать список этому свойству, даже пытался присвоить -1 SelectedIndex перед отвязкой, но ни один из них не помог.

[Изменить]

Меня попросили показать код. Я вставлю соответствующие фрагменты:

<сильный>1. Классное лицо:

public class Person
{
    private int id;
    private string name;

    public Person(int m_id, string m_name)
    {
        id = m_id;
        name = m_name;
    }

    public int Id
    {
        get
        {
            return id;
        }
    }

    public string Name
    {
        get
        {
            return name;
        }
    }
}`

<сильный>2. В конструкторе формы:

List<Person> persons = new List<Person>();

<сильный>3. В методе, запущенном на кнопке 1, нажмите:

listBox1.DataSource = null;    // this is optional. Commenting this line out doesn't help
persons.Add(new Person(1, "John Doe"));
persons.Add(new Person(2, "Jane Doe"));
persons.Add(new Person(3, "Somebody Else"));
listBox1.ValueMember = "Id";
listBox1.DisplayMember = "Name";
listBox1.DataSource = persons;

<сильный>4. В методе, запущенном на кнопке2, нажмите:

listBox1.DataSource = null;    // this is optional. Commenting this line out doesn't help
persons.Add(new Person(1, "Person One"));
persons.Add(new Person(2, "Person Two"));
listBox1.ValueMember = "Id";
listBox1.DisplayMember = "Name";
listBox1.DataSource = persons;

Когда я нажимаю кнопку 1, список заполняется, и все работает нормально. Когда я выбираю последний элемент («Кто-то еще»), а затем нажимаю кнопку 2, в списке отображаются 2 идентичных элемента: «MyNamespace.Person».

[Редактировать 2 — полный код формы]

using System;
using System.Collections.Generic;
using System.Windows.Forms;

namespace MyNamespace
{
    public partial class Form1 : Form
    {
        private List<Person> persons = new List<Person>();
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            persons.Clear();
            persons.Add(new Person(1, "John Doe"));
            persons.Add(new Person(2, "Jane Doe"));
            persons.Add(new Person(1, "Somebody Else"));
            listBox1.DataSource = null;
            listBox1.ValueMember = "Id";
            listBox1.DisplayMember = "Name";
            listBox1.DataSource = persons;
        }

        private void button2_Click(object sender, EventArgs e)
        {
            persons.Clear();
            persons.Add(new Person(1, "Person One"));
            persons.Add(new Person(2, "Person Two"));
            listBox1.DataSource = null;
            listBox1.ValueMember = "Id";
            listBox1.DisplayMember = "Name";
            listBox1.DataSource = persons;
        }
    }

    class Person
    {
        private int id;
        private string name;

        public Person(int m_id, string m_name)
        {
            id = m_id;
            name = m_name;
        }

        public int Id
        {
            get
            {
                return id;
            }
        }

        public string Name
        {
            get
            {
                return name;
            }
        }

        public string ToString()
        {
            return id + ". " + name;
        }
    }
}

Действия по воспроизведению проблемы:

  1. Запустить форму
  2. Нажмите кнопку1
  3. Выберите последнюю позицию в списке ("Кто-то еще")
  4. Нажмите кнопку2

Если вы выберете «John Doe» или «Jane Doe» в списке, все будет работать нормально. Кажется, что это «сбой», когда выбранный индекс недействителен после перестроения списка. Я думаю, это какой-то баг.


person peterp    schedule 25.05.2014    source источник
comment
Вы должны показать свой код, чтобы мы могли вам помочь.   -  person LarsTech    schedule 25.05.2014
comment
Я не могу воспроизвести вашу проблему... Я попробовал ваш код, и он отлично работает на обеих кнопках... без переопределения ToString()   -  person Lev Z    schedule 26.05.2014


Ответы (2)


Когда кто-то устанавливает DataSource в null, он очищает значение DisplayMember. Поэтому для решения установите его после установки нового DataSource, и проблема исчезнет.

listBox1.DataSource = null;    // this is optional. Commenting this line out doesn't help
persons.Add(new Person(1, "John Doe"));
persons.Add(new Person(2, "Jane Doe"));
persons.Add(new Person(3, "Somebody Else"));
listBox1.DataSource = persons;
listBox1.DisplayMember = "Name";

В противном случае в классе Person переопределите метод ToString, чтобы убедиться, что правильное свойство будет отображаться, если DataMember пусто:

public class Person
{
    private int id;
    private string name;

    public Person(int m_id, string m_name)
    {
        id = m_id;
        name = m_name;
    }

    public int Id
    {
        get
        {
            return id;
        }
    }

    public string Name
    {
        get
        {
            return name;
        }
    }
    public override string ToString()
    {
        return name;
    }
}

При этом всякий раз, когда вы устанавливаете источник данных списка на List<Person>, список будет автоматически использовать метод ToString в качестве отображения. Использование выбранного элемента — это просто приведение его к типу Person, (Person)listBox1.SelectedItem.

person tinstaafl    schedule 25.05.2014
comment
Извините, я забыл упомянуть: я уже переопределил этот метод, и, как я сказал в первом посте, список показывает соответствующее содержимое, если недавно выбранный индекс не слишком велик в соответствии с новым содержимым списка. На данный момент установка этого индекса на 0 непосредственно перед перезагрузкой списка решает проблему. Это довольно протетично, но работает - person peterp; 26.05.2014
comment
@peterp - Ваш код должен делать что-то еще. Как бы я ни старался, я не могу повторить ваши результаты. Единственный способ заставить список отображать имя класса — удалить переопределение ToString. - person tinstaafl; 26.05.2014
comment
Нет, мой пример кода не больше, чем я вставил. Я собираюсь показать весь код, который приводит к такому странному поведению. - person peterp; 26.05.2014
comment
@peterp - Извините, что так долго. Я смог продублировать вашу проблему и добавил ответ для вас. - person tinstaafl; 26.05.2014
comment
Благодарю за ваш ответ. Как видите, я показал полный код. Он реализует ToString() с классом Person, а также переназначает DisplayMember после listBox1.DataSource = null. Таким образом, единственное, что может вызвать проблему, — это место, где я переназначаю свой список на DataSource. Это, очевидно, должно идти до установки DisplayMember. Спасибо, что указали на это! - person peterp; 26.05.2014

Попробуйте установить свойства "ValueMember" и "DisplayMember" только один раз перед любой привязкой к источнику данных. Можно ли установить их в дизайнере? Затем всегда перед изменением источника данных запускайте метод ListBox "ClearSelected()", чтобы очистить все выборки. Затем отмените привязку источника данных, отредактируйте список, затем установите отредактированный список в качестве источника данных. Похоже, такое поведение является своего рода ошибкой. Попробуйте, если это поможет.

person W0lfw00ds    schedule 26.05.2014