代码之家  ›  专栏  ›  技术社区  ›  Adam Tegen

在WinForms中向Listview添加按钮

  •  23
  • Adam Tegen  · 技术社区  · 15 年前

    有没有办法在WinForms应用程序的ListView中向单元格添加按钮控件?

    10 回复  |  直到 15 年前
        1
  •  18
  •   Simon Mourier    14 年前

    这是一个类的代码 ListViewExtender ListView ,基本上您只需声明特定列显示为按钮而不是文本。按钮的文本是子项的文本。

    它允许无问题的大型列表视图,不使用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<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(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<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, 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);
                }
            }
        }
    }
    
        2
  •  14
  •   Ryan Farley    15 年前
        3
  •  7
  •   AZ.    13 年前

    这是 最好的
    ObjectListView

        4
  •  3
  •   pinker    12 年前

    要使Simon Mourier的扩展器工作,缺少以下行:

    extender.AddColumn(buttonAction);
    

    这看起来应该是:

    ListViewExtender extender = new ListViewExtender(listSummary);
    ListViewButtonColumn buttonAction = new ListViewButtonColumn(2);
    buttonAction.Click += OnButtonActionClick;
    buttonAction.FixedWidth = true;
    extender.AddColumn(buttonAction);
    
        6
  •  1
  •   walterbing1    14 年前

    不,标准的Windows窗体列表视图不支持嵌入控件。您可以尝试构建自己的自定义控件,也可以使用 http://www.codeproject.com/KB/list/EXListView.aspx .

        7
  •  1
  •   Andrei Pana    14 年前

    也许值得一提的是,列表视图控件可以在WPF中设计为一个用户控件/自定义控件,其ListViewItems中有按钮,然后在WinForms应用程序中使用该控件,在 ElementHost

        8
  •  0
  •   Marzena    14 年前

    不,是的,ListView本身不支持这样的功能,但是您可以在它上面创建一个按钮,这样它在用户看来就是ListView的一部分。(我想这也是上面提到的ExtendedListView所做的)。

        9
  •  0
  •   Hoàng Long    14 年前
        10
  •  0
  •   ejderuby    5 年前

    你可以用一个 GlacialList

    如果你有 System.IO.FileNotFoundException InitializeComponent()

    下面是它的外观示例:

    example

        11
  •  -2
  •   Favonius    12 年前

    这看起来是我遇到的最简单的答案。。。刚加了一个 ItemCommand ListView

    请参阅此链接: handle-the-button-click-event-from-an-asp-net-listview-control