C#自定义列表框的GUI [英] C# custom listbox GUI

查看:136
本文介绍了C#自定义列表框的GUI的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个类的列表,但不同的孩子有需要显示不同的属性。

I have a list of classes, but different children have different properties that need to be displayed.

我想实现是有一个列表框型控制在使每个子以显示它的属性,它希望的方式的GUI - 所以不使用每个类别相同的预先定义的列

What I want to achieve is to have a listbox-type control in the gui which enables each child to display it's properties the way it wants to - so not using the same pre-defined columns for every class.

我设想类似的传输接口(下图),每个类都可以绘制它自己的条目,显示出一些文字,进度条如果相关,等等

I envisage something like the transmission interface (below), where each class can paint it's own entry, showing some text, progress bar if relevant, etc.

如何在C#实现?

感谢您的帮助。

推荐答案

让您的列表项目实施提供一切所需的接口为显示:

Let your list items implement an interface that provides everything needed for the display:

public interface IDisplayItem
{
    event System.ComponentModel.ProgressChangedEventHandler ProgressChanged;
    string Subject { get; }
    string Description { get; }
    // Provide everything you need for the display here
}



传输对象不应该展示自己。你不应该混合域逻辑(业务逻辑)和显示逻辑

The transmission objects should not display themselves. You should not mix domain logic (business logic) and display logic.

修改#1
为了做到这显示列表框项目你自己的方式,你将不得不得出从 System.Windows.Forms.ListBox 你自己的ListBox控件。您的列表框的 DrawMode 属性设置为 DrawMode.OwnerDrawFixed DrawMode.OwnerDrawVariable (如果项目具有相同的尺寸的不)。如果你使用 OwnerDrawVariable 那么你将不得不重写 OnMeasureItem的为好,以告诉列表框的每个大小。项目

EDIT #1: In order to do display listbox items your own way, you will have to derive your own listbox control from System.Windows.Forms.ListBox. Set the DrawMode property of your listbox to DrawMode.OwnerDrawFixed or DrawMode.OwnerDrawVariable (if the items are not of the same size) in the constructor. If you use OwnerDrawVariable then you will have to override OnMeasureItem as well, in order to tell the listbox the size of each item.

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 或创建一个特殊类用于此目的。也可以有不同类型的列表中的对象的,只要它们实现的接口。问题的关键是,该显示器逻辑本身是在控制,传输类(或其他类)只提供所需的信息。

You can let your original transmission class implement IDisplayItem or create a special class for this purpose. You can also have different types of objects in the list, as long as they implement the interface. The point is, that the display logic itself is in the control, the transmission class (or whatever class) only provides the information required.

编辑#2
,因为与马克进行的讨论中,我决定在这里包括一个完整的示例。让我们定义一个模型类:

EDIT #2: Because of the ongoing discussion with Mark, I have decided to include a full example here. Let's define a model class:

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
}

下面是一个自定义列表框:

Here is a custom 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和一个按钮。在表格中,我们将一些初始化代码和一些按钮的代码,这改变了我们的地址。我们才能看到,这样做,如果我们的列表框会自动更新:

On a form, we place this AddressListBox and a button. In the form, we place some initializing code and some button code, which changes our addresses. We do this in order to see, if our listbox is updated automatically:

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项目自动更新。请注意,只有列表框的数据源定义。该数据成员和ValueMember保持空白。

When the button is clicked, the items in the AddressListBox are updated automatically. Note that only the DataSource of the listbox is defined. The DataMember and ValueMember remain empty.

这篇关于C#自定义列表框的GUI的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆