Пусть ваши элементы списка реализуют интерфейс, который предоставляет все необходимое для отображения:
public interface IDisplayItem
{
event System.ComponentModel.ProgressChangedEventHandler ProgressChanged;
string Subject { get; }
string Description { get; }
// Provide everything you need for the display here
}
Объекты передачи не должны отображаться сами по себе.Вы не должны смешивать доменную логику (бизнес-логику) и логику отображения.
Настроенный ListBox : чтобы отображать элементы списка по-своему, вам придется извлечь собственный элемент управления списка изSystem.Windows.Forms.ListBox
.Установите свойство DrawMode
вашего списка в DrawMode.OwnerDrawFixed
или DrawMode.OwnerDrawVariable
(если элементы не одного размера) в конструкторе.Если вы используете OwnerDrawVariable
, то вам также придется переопределить OnMeasureItem
, чтобы сообщить списку размер каждого элемента.
public class TransmissionListBox : ListBox
{
public TransmissionListBox()
{
this.DrawMode = DrawMode.OwnerDrawFixed;
}
protected override void OnDrawItem(DrawItemEventArgs e)
{
e.DrawBackground();
if (e.Index >= 0 && e.Index < Items.Count) {
var displayItem = Items[e.Index] as IDisplayItem;
TextRenderer.DrawText(e.Graphics,displayItem.Subject,e.Font,...);
e.Graphics.DrawIcon(...);
// and so on
}
e.DrawFocusRectangle();
}
}
Вы можете позволить вашему исходному классу передачи реализовать IDisplayItem
или создать специальный класс для этой цели.Вы также можете иметь различные типы объектов в списке, если они реализуют интерфейс.Дело в том, что сама логика дисплея находится в элементе управления, класс передачи (или любой другой класс) предоставляет только требуемую информацию.
Пример : из-за продолжающегося обсуждения с Марком,Я решил включить полный пример здесь.Давайте определим класс модели:
public class Address : INotifyPropertyChanged
{
private string _Name;
public string Name
{
get { return _Name; }
set
{
if (_Name != value) {
_Name = value;
OnPropertyChanged("Name");
}
}
}
private string _City;
public string City
{
get { return _City; }
set
{
if (_City != value) {
_City = value;
OnPropertyChanged("City");
OnPropertyChanged("CityZip");
}
}
}
private int? _Zip;
public int? Zip
{
get { return _Zip; }
set
{
if (_Zip != value) {
_Zip = value;
OnPropertyChanged("Zip");
OnPropertyChanged("CityZip");
}
}
}
public string CityZip { get { return Zip.ToString() + " " + City; } }
public override string ToString()
{
return Name + "," + CityZip;
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null) {
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
Вот пользовательский ListBox:
public class AddressListBox : ListBox
{
public AddressListBox()
{
DrawMode = DrawMode.OwnerDrawFixed;
ItemHeight = 18;
}
protected override void OnDrawItem(DrawItemEventArgs e)
{
const TextFormatFlags flags = TextFormatFlags.Left | TextFormatFlags.VerticalCenter;
if (e.Index >= 0) {
e.DrawBackground();
e.Graphics.DrawRectangle(Pens.Red, 2, e.Bounds.Y + 2, 14, 14); // Simulate an icon.
var textRect = e.Bounds;
textRect.X += 20;
textRect.Width -= 20;
string itemText = DesignMode ? "AddressListBox" : Items[e.Index].ToString();
TextRenderer.DrawText(e.Graphics, itemText, e.Font, textRect, e.ForeColor, flags);
e.DrawFocusRectangle();
}
}
}
На форме мы помещаем этот AddressListBox и кнопку.В форме мы помещаем некоторый инициализирующий код и некоторый код кнопки, который меняет наши адреса.Мы делаем это для того, чтобы увидеть, обновляется ли наш список автоматически:
public partial class frmAddress : Form
{
BindingList<Address> _addressBindingList;
public frmAddress()
{
InitializeComponent();
_addressBindingList = new BindingList<Address>();
_addressBindingList.Add(new Address { Name = "Müller" });
_addressBindingList.Add(new Address { Name = "Aebi" });
lstAddress.DataSource = _addressBindingList;
}
private void btnChangeCity_Click(object sender, EventArgs e)
{
_addressBindingList[0].City = "Zürich";
_addressBindingList[1].City = "Burgdorf";
}
}
Когда кнопка нажата, элементы в AddressListBox обновляются автоматически.Обратите внимание, что определяется только DataSource из списка.DataMember и ValueMember остаются пустыми.