C # настраиваемый список GUI - PullRequest
4 голосов
/ 16 ноября 2011

У меня есть список классов, но разные дети имеют разные свойства, которые должны отображаться.

Чего я хочу добиться, так это иметь элемент управления типа списка в графическом интерфейсе, который позволяет каждому дочернему элементу отображать свои свойства так, как он хочет - поэтому не следует использовать одинаковые предварительно определенные столбцы для каждого класса.

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

enter image description here

Как этого можно достичь в C #?

Спасибо за любую помощь.

Ответы [ 2 ]

13 голосов
/ 16 ноября 2011

Пусть ваши элементы списка реализуют интерфейс, который предоставляет все необходимое для отображения:

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 остаются пустыми.

1 голос
/ 16 ноября 2011

да, если вы используете WPF, это довольно легко сделать. Все, что вам нужно сделать, это сделать разные DataTemplate для ваших разных типов.

MSDN для шаблонов данных
Dr. WPF для элементов управления и шаблонов данных

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