How can I link class instances and ListBox values?
There is a ListBox to which elements are added using a loop, each ListBox element is a property of a class instance in a string representation(there are several instances of the class and they are combined into an array). You need to make it possible to edit an instance of the class by selecting the appropriate element in the ListBox
1 answers
You can put any objects in the ListBox
component, including objects of different types.
In this case, the list will display the text that gives the virtual method ToString()
of the Object
class for the displayed object.
(let me remind you that the Object
class is the very first "progenitor" of any class, even when you don't explicitly inherit your class from anything).
Accordingly, the options for solving the problem are:
- In its own class, which describes the subject matter to be solved scope, redefine the
ToString()
method so that it outputs the desired text. Throw objects of this class intoListBox
, andListBox
will display the output of theToString()
method. - If the first option is not suitable (for example, it is not possible to make changes to an existing class), then you can create a new wrapper class, in which we redefine the
ToString()
method and give a reference to the object to be edited. - If you are going to put objects of the same type( class), and this class has public property with a suitable one (to be displayed in the list) with a text value, then specify the name of this property in the
ValueMember
property of theListBox
component. (if there is no property with the specified name, the element text will be taken fromToString()
)
In any case, to access the selected object, we refer to the SelectedItem
property of the ListBox
component - this property is expected to have the type Object
, so do not forget to cast it to the desired type.
Demo code example (a simple form with a single ListBox component):
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
// вариант 1
listBox1.Items.Add((int) 1);
listBox1.Items.Add((long) 2);
listBox1.Items.Add((char) '3');
listBox1.Items.Add((string) "4");
listBox1.Items.Add((Type) typeof(Form1));
// вариант 2
listBox1.Items.Add(new ObjectInfo(typeof(Form1), "'typeof(Form1)' (reflection)"));
listBox1.Items.Add(new ObjectInfo(this, "This Form"));
listBox1.Items.Add(new ObjectInfo(listBox1, "This ListBox object"));
/*
альтернативный (3) вариант: отображать свойство "Name";
сработает для последних 4-х элементов списка (типы разные, но свойство с именем "Name" имеют)
(для первых же 4-х элементов списка будет отображена выдача метода "ToString()", за неимением свойства "Name")
*/
// listBox1.ValueMember = "Name";
}
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (listBox1.SelectedItem is ObjectInfo oi)
MessageBox.Show($"Выбран элемент: '{oi.Name}' класса '{oi.Object.GetType().Name}'");
}
}
// класс для объекта-обёртки
public class ObjectInfo
{
public Object Object { get; private set; }
public string Name { get; private set; }
// ... прочие свойства и методы
public ObjectInfo(Object obj, string name)
{
this.Object = obj;
this.Name = name;
// ... прочая инициализация
}
// здесь вернём то, что хотим видеть в "ListBox" по дефолту
// (при закомментированной строке с "listBox1.ValueMember")
public override string ToString()
{
return $"'{Name}' of type '{Object.GetType().Name}'";
}
}