C#自定义列表框GUI

C#自定义列表框GUI,c#,winforms,list,user-interface,C#,Winforms,List,User Interface,我有一个类列表,但是不同的子类有不同的属性需要显示 我想要实现的是在gui中有一个listbox类型控件,它使每个子级都能够以它想要的方式显示它的属性,因此不必为每个类使用相同的预定义列 我设想了一些类似于传输接口(如下)的东西,其中每个类都可以绘制自己的条目,显示一些文本、进度条(如果相关)等等 如何在C#中实现这一点 谢谢您的帮助。是的,如果您使用WPF,那么很容易做到这一点。您所要做的就是为不同的类型制作不同的DataTemplate 让列表项实现一个界面,提供显示所需的一切: pub

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

我想要实现的是在gui中有一个listbox类型控件,它使每个子级都能够以它想要的方式显示它的属性,因此不必为每个类使用相同的预定义列

我设想了一些类似于传输接口(如下)的东西,其中每个类都可以绘制自己的条目,显示一些文本、进度条(如果相关)等等

如何在C#中实现这一点


谢谢您的帮助。

是的,如果您使用WPF,那么很容易做到这一点。您所要做的就是为不同的类型制作不同的
DataTemplate



让列表项实现一个界面,提供显示所需的一切:

public interface IDisplayItem
{
    event System.ComponentModel.ProgressChangedEventHandler ProgressChanged;
    string Subject { get; }
    string Description { get; }
    // Provide everything you need for the display here
}
传输对象不应显示自己。您不应该混合使用域逻辑(业务逻辑)和显示逻辑

自定义列表框: 为了以自己的方式显示列表框项目,您必须从
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();
    }
}
这是一个自定义列表框:

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();
        }
    }
}
在表单上,我们放置这个地址列表框和一个按钮。在表单中,我们放置了一些初始化代码和一些按钮代码,这会更改我们的地址。我们这样做是为了查看列表框是否自动更新:

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";
    }
}
公共部分类frmAddress:表单
{
BindingList\u addressBindingList;
公共服装()
{
初始化组件();
_addressBindingList=新建BindingList();
_addressBindingList.Add(新地址{Name=“Müller”});
_addressBindingList.Add(新地址{Name=“Aebi”});
lstAddress.DataSource=\u addressBindingList;
}
私有void btnChangeCity\u单击(对象发送者,事件参数e)
{
_addressBindingList[0]。City=“Zürich”;
_addressBindingList[1]。City=“Burgdorf”;
}
}

单击按钮时,AddressListBox中的项目将自动更新。请注意,仅定义了listbox的数据源。DataMember和ValueMember仍然为空。

Silverlight、WPF或WinForms?C不是GUI,您使用什么GUI工具包?Winforms?WPF?SilverLight?不幸的是,我在WinForms上。很抱歉没有在我原来的帖子里说。但是WPF的链接看起来很棒——这正是我想做的事情。我不太明白。那么,您是否有一个单独的类来处理显示、绑定到列表项并可以添加到listbox控件?那么,是否可能有不同的物品显示不同的属性?你有任何链接或例子来进一步解释这一点吗?谢谢谢谢你的更新。我要试一试!它肯定会给我一个学习的起点。在WinForms中,通过调用Invalidate()方法(或重载之一)触发控件的重新绘制<代码>myListBox.Invalidate()
IDisplayItem
接口可以有一个
float Progress{get;}
属性,该属性公开传输的当前状态。每次更改
IDisplayItem
公开的属性时,必须使列表框无效。另一种方法是使用数据绑定。将列表框绑定到对象绑定源,并在显示的项目中实现
INotifyPropertyChanged
。数据绑定的魔力将使列表框自动显示更改!我做了一些测试。如果使用
System.ComponentModel.BindingList
,它似乎工作得更好。在我的测试中,我将列表转换为绑定列表:
var bindingslist=newbindingslist(addressList);addressBindingSource.DataSource=bindingList。我没有设置Display(显示)或ValueMember(值成员)。好的,我以前的语句基于一个代码,这也做了其他事情,导致了混乱。我决定做一个完整的例子,以创造清楚的事实(见编辑#2)。标记您是对的,如果使用了
BindingList
,则不需要
BindingSource
。该示例仅使用
绑定列表
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";
    }
}