Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding button into a Listview in WinForms

Is there a way to add a button control to a cell in inside a ListView in a WinForms app?

like image 841
Adam Tegen Avatar asked Jan 18 '09 22:01

Adam Tegen


People also ask

How do I add a button in Visual Studio Form?

Select the new FlowLayoutPanel, and then open the Toolbox and select Common Controls. Double-click the Button item to add a button control called button1. Double-click Button again to add another button.

What is a ListView subitem?

The Windows Forms ListView control can display additional text, or subitems, for each item in the Details view. The first column displays the item text, for example an employee number. The second, third, and subsequent columns display the first, second, and subsequent associated subitems.

What is ListView control in C#?

C# ListView control provides an interface to display a list of items using different views including text, small images, and large images.


2 Answers

Here is a code of a class ListViewExtender that you can reuse. It's not a derived class of ListView, basically you just declare that a specific column is displayed as buttons instead of text. The button's text is the subItem's text.

It allows big sized list views without problems, does not use p/invoke, and also works with horizontal scrollbars (some code proposed as answers here don't or are quite slow with a great number of items). Note it requires the extended ListView to have FullRowSelect set to true and view type set to Details.

This is a sample code that uses it:

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);         }     } } 

Here is the ListViewExtender code and associated classes:

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);             }         }     } } 
like image 52
Simon Mourier Avatar answered Sep 21 '22 08:09

Simon Mourier


The ListView itself (or ListViewItem) does not function as a container of any kind so no way to add controls directly, however it is doable. I have used this extended ListView with a lot of success: Embedding Controls in a ListView.

like image 39
Ryan Farley Avatar answered Sep 20 '22 08:09

Ryan Farley