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