有没有办法在WinForms应用程序中的ListView内向单元格添加按钮控件?
这是ListViewExtender
您可以重用的类的代码.它不是派生类ListView
,基本上你只是声明一个特定的列显示为按钮而不是文本.按钮的文本是subItem的文本.
它允许没有问题的大型列表视图,不使用p/invoke,也可以使用水平滚动条(这里提出的一些代码作为答案,或者对于大量项目来说非常慢).请注意,它需要扩展ListView FullRowSelect
设置为true
和查看类型设置为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_columns = new Dictionary (); 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(e.X, e.Y, 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(e.X, e.Y, 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 Columns { get { return _columns.Values; } } public virtual void Dispose() { if (Font != null) { Font.Dispose(); Font = null; } } } public abstract class ListViewColumn { public event EventHandler 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, e.X, e.Y, 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)不能作为任何类型的容器运行,因此无法直接添加控件,但它是可行的.我已经使用了这个扩展的ListView并取得了很大的成功:在ListView中嵌入控件.
这是WinForms 的最佳自定义列表视图控件.
ObjectListView