public partial class TestConrol : UserControl
{
public TestConrol()
{
InitializeComponent();
}
public override string ToString()
{
return "asd";
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
TestConrol tc1 = new TestConrol();
comboBox1.Items.Add(tc1);
TestConrol tc2 = new TestConrol();
comboBox1.Items.Add(tc2);
}
}
When form loaded, I see combobox has two items with empty names, instead of "asd" :/
But this work if I override ToString() in common class, not derived from anything:
public class TestClass
{
public override string ToString()
{
return "bla bla bla";
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
TestClass tcl = new TestClass();
comboBox1.Items.Add(tcl);
}
}
After that I see in combobox "bla bla bla"
I tried to understand the source code(!). This is not a simple call to ToString()
.
There's an internal
class System.Windows.Forms.Formatter
doing some stuff. It eventually creates a converter. This is roughly equivalent to saying:
var conv = System.ComponentModel.TypeDescriptor.GetConverter(tc1.GetType());
where tc1
is the TestContol
from your question. Now, had we used the TestClass
tcl
which doesn't implement any interfaces, this would have given us a converter which would eventually call ToString()
.
But in this example we use tc1
, and it is a System.ComponentModel.IComponent
. Our conv
therefore becomes a System.ComponentModel.ComponentConverter
. It uses the Site
of the IComponent
. When we say:
string result = conv.ConvertTo(tc1, typeof(string));
and the Site
is null, we get the empty string ""
you saw in your combo box. Had there been a Site
it would have used its Name
instead.
To demonstrate that, put the following into your TestControl
instance constructor:
public TestConrol()
{
InitializeComponent();
Site = new DummySite(); // note: Site is public, so you can also
// write to it from outside the class.
// It is also virtual, so you can override
// its getter and setter.
}
where DummySite
is something like:
class DummySite : ISite
{
public IComponent Component
{
get { throw new NotImplementedException(); }
}
public IContainer Container
{
get { throw new NotImplementedException(); }
}
public bool DesignMode
{
get { throw new NotImplementedException(); }
}
public string Name
{
get
{
return "asd"; // HERE'S YOUR TEXT
}
set
{
throw new NotImplementedException();
}
}
public object GetService(Type serviceType)
{
return null;
}
}