在WinForms中将button添加到Listview中
有没有办法将一个button控件添加到WinForms应用程序中的ListView中的单元格?
这是一个可以重用的类ListViewExtender
的代码。 它不是ListView
的派生类,基本上你只是声明一个特定的列被显示为button而不是文本。 button的文本是子项的文本。
它允许大尺寸列表视图没有问题,不使用p / invoke,也可以使用水平滚动条(这里提供的一些代码作为答案没有或很慢的项目很多)。 请注意,它需要扩展的ListView将FullRowSelect
设置为true
并将查看types设置为Details
。
这是一个使用它的示例代码:
namespace WindowsFormsApplication1 { public partial class Form1 : Form { public Form1() { InitializeComponent(); // you need to add a listView named listView1 with the designer listView1.FullRowSelect = true; ListViewExtender extender = new ListViewExtender(listView1); // extend 2nd column ListViewButtonColumn buttonAction = new ListViewButtonColumn(1); buttonAction.Click += OnButtonActionClick; buttonAction.FixedWidth = true; extender.AddColumn(buttonAction); for (int i = 0; i < 10000; i++) { ListViewItem item = listView1.Items.Add("item" + i); item.SubItems.Add("button " + i); } } private void OnButtonActionClick(object sender, ListViewColumnMouseEventArgs e) { MessageBox.Show(this, @"you clicked " + e.SubItem.Text); } } }
这里是ListViewExtender的代码和关联的类:
using System; using System.Collections.Generic; using System.Drawing; using System.Windows.Forms; using System.Windows.Forms.VisualStyles; namespace WindowsFormsApplication1 { public class ListViewExtender : IDisposable { private readonly Dictionary<int, ListViewColumn> _columns = new Dictionary<int, ListViewColumn>(); public ListViewExtender(ListView listView) { if (listView == null) throw new ArgumentNullException("listView"); if (listView.View != View.Details) throw new ArgumentException(null, "listView"); ListView = listView; ListView.OwnerDraw = true; ListView.DrawItem += OnDrawItem; ListView.DrawSubItem += OnDrawSubItem; ListView.DrawColumnHeader += OnDrawColumnHeader; ListView.MouseMove += OnMouseMove; ListView.MouseClick += OnMouseClick; Font = new Font(ListView.Font.FontFamily, ListView.Font.Size - 2); } public virtual Font Font { get; private set; } public ListView ListView { get; private set; } protected virtual void OnMouseClick(object sender, MouseEventArgs e) { ListViewItem item; ListViewItem.ListViewSubItem sub; ListViewColumn column = GetColumnAt(eX, eY, out item, out sub); if (column != null) { column.MouseClick(e, item, sub); } } public ListViewColumn GetColumnAt(int x, int y, out ListViewItem item, out ListViewItem.ListViewSubItem subItem) { subItem = null; item = ListView.GetItemAt(x, y); if (item == null) return null; subItem = item.GetSubItemAt(x, y); if (subItem == null) return null; for (int i = 0; i < item.SubItems.Count; i++) { if (item.SubItems[i] == subItem) return GetColumn(i); } return null; } protected virtual void OnMouseMove(object sender, MouseEventArgs e) { ListViewItem item; ListViewItem.ListViewSubItem sub; ListViewColumn column = GetColumnAt(eX, eY, out item, out sub); if (column != null) { column.Invalidate(item, sub); return; } if (item != null) { ListView.Invalidate(item.Bounds); } } protected virtual void OnDrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e) { e.DrawDefault = true; } protected virtual void OnDrawSubItem(object sender, DrawListViewSubItemEventArgs e) { ListViewColumn column = GetColumn(e.ColumnIndex); if (column == null) { e.DrawDefault = true; return; } column.Draw(e); } protected virtual void OnDrawItem(object sender, DrawListViewItemEventArgs e) { // do nothing } public void AddColumn(ListViewColumn column) { if (column == null) throw new ArgumentNullException("column"); column.Extender = this; _columns[column.ColumnIndex] = column; } public ListViewColumn GetColumn(int index) { ListViewColumn column; return _columns.TryGetValue(index, out column) ? column : null; } public IEnumerable<ListViewColumn> Columns { get { return _columns.Values; } } public virtual void Dispose() { if (Font != null) { Font.Dispose(); Font = null; } } } public abstract class ListViewColumn { public event EventHandler<ListViewColumnMouseEventArgs> Click; protected ListViewColumn(int columnIndex) { if (columnIndex < 0) throw new ArgumentException(null, "columnIndex"); ColumnIndex = columnIndex; } public virtual ListViewExtender Extender { get; protected internal set; } public int ColumnIndex { get; private set; } public virtual Font Font { get { return Extender == null ? null : Extender.Font; } } public ListView ListView { get { return Extender == null ? null : Extender.ListView; } } public abstract void Draw(DrawListViewSubItemEventArgs e); public virtual void MouseClick(MouseEventArgs e, ListViewItem item, ListViewItem.ListViewSubItem subItem) { if (Click != null) { Click(this, new ListViewColumnMouseEventArgs(e, item, subItem)); } } public virtual void Invalidate(ListViewItem item, ListViewItem.ListViewSubItem subItem) { if (Extender != null) { Extender.ListView.Invalidate(subItem.Bounds); } } } public class ListViewColumnMouseEventArgs : MouseEventArgs { public ListViewColumnMouseEventArgs(MouseEventArgs e, ListViewItem item, ListViewItem.ListViewSubItem subItem) : base(e.Button, e.Clicks, eX, eY, e.Delta) { Item = item; SubItem = subItem; } public ListViewItem Item { get; private set; } public ListViewItem.ListViewSubItem SubItem { get; private set; } } public class ListViewButtonColumn : ListViewColumn { private Rectangle _hot = Rectangle.Empty; public ListViewButtonColumn(int columnIndex) : base(columnIndex) { } public bool FixedWidth { get; set; } public bool DrawIfEmpty { get; set; } public override ListViewExtender Extender { get { return base.Extender; } protected internal set { base.Extender = value; if (FixedWidth) { base.Extender.ListView.ColumnWidthChanging += OnColumnWidthChanging; } } } protected virtual void OnColumnWidthChanging(object sender, ColumnWidthChangingEventArgs e) { if (e.ColumnIndex == ColumnIndex) { e.Cancel = true; e.NewWidth = ListView.Columns[e.ColumnIndex].Width; } } public override void Draw(DrawListViewSubItemEventArgs e) { if (_hot != Rectangle.Empty) { if (_hot != e.Bounds) { ListView.Invalidate(_hot); _hot = Rectangle.Empty; } } if ((!DrawIfEmpty) && (string.IsNullOrEmpty(e.SubItem.Text))) return; Point mouse = e.Item.ListView.PointToClient(Control.MousePosition); if ((ListView.GetItemAt(mouse.X, mouse.Y) == e.Item) && (e.Item.GetSubItemAt(mouse.X, mouse.Y) == e.SubItem)) { ButtonRenderer.DrawButton(e.Graphics, e.Bounds, e.SubItem.Text, Font, true, PushButtonState.Hot); _hot = e.Bounds; } else { ButtonRenderer.DrawButton(e.Graphics, e.Bounds, e.SubItem.Text, Font, false, PushButtonState.Default); } } } }
ListView本身(或ListViewItem)不能作为任何types的容器,所以没有办法直接添加控件,但它是可行的。 我已经使用这个扩展的ListView成功了很多: 在ListView中embedded控件 。
这是WinForms的最佳自定义列表视图控件。
ObjectListView
为了使Simon Mourier工作的扩展器缺less以下行:
extender.AddColumn(buttonAction);
这是,它应该看起来像:
ListViewExtender extender = new ListViewExtender(listSummary); ListViewButtonColumn buttonAction = new ListViewButtonColumn(2); buttonAction.Click += OnButtonActionClick; buttonAction.FixedWidth = true; extender.AddColumn(buttonAction);
不,标准Windows窗体ListView不支持embedded式控件。 你可以尝试构build你自己的自定义控件,或者你可以使用像http://www.codeproject.com/KB/list/EXListView.aspx 。
也许值得一提的是,列表视图控件可能在WPF中被devise为一个在ListViewItems中带有button的用户控件/自定义控件,然后在WinForms应用程序的ElementHost控件中使用该控件。
不,是的,ListView本身不支持这样的function,但是你可以在它上面创build一个button,这样用户就会把它看作是列表视图的组成部分。 (我想这是上面提到的ExtendedListView也是这样)。
我以前偶然遇到过一个讨论,希望这个帮助: http : //social.msdn.microsoft.com/Forums/en-US/winforms/thread/ee232cc4-68c5-4ed3-9ea7-d4d999956504/
这看起来像我遇到的最简单的答案…只是添加一个ItemCommand
到ListView
。
看到这个链接: 处理button点击事件从一个ASPnetworking列表视图控制