using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace ListViewEmbeddedControls
{
///
/// Zusammenfassung für ListViewEx.
///
public class ListViewEx : ListView
{
#region Interop-Defines
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wPar, IntPtr lPar);
// ListView messages
private const int LVM_FIRST = 0x1000;
private const int LVM_GETCOLUMNORDERARRAY = (LVM_FIRST + 59);
// Windows Messages
private const int WM_PAINT = 0x000F;
#endregion
///
/// Structure to hold an embedded control's info
///
private struct EmbeddedControl
{
public Control Control;
public int Column;
public int Row;
public DockStyle Dock;
public ListViewItem Item;
}
private ArrayList _embeddedControls = new ArrayList();
public ListViewEx() {}
///
/// Retrieve the order in which columns appear
///
/// Current display order of column indices
protected int[] GetColumnOrder()
{
IntPtr lPar = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(int)) * Columns.Count);
IntPtr res = SendMessage(Handle, LVM_GETCOLUMNORDERARRAY, new IntPtr(Columns.Count), lPar);
if (res.ToInt32() == 0) // Something went wrong
{
Marshal.FreeHGlobal(lPar);
return null;
}
int [] order = new int[Columns.Count];
Marshal.Copy(lPar, order, 0, Columns.Count);
Marshal.FreeHGlobal(lPar);
return order;
}
///
/// Retrieve the bounds of a ListViewSubItem
///
/// The Item containing the SubItem
/// Index of the SubItem
/// Subitem's bounds
protected Rectangle GetSubItemBounds(ListViewItem Item, int SubItem)
{
Rectangle subItemRect = Rectangle.Empty;
if (Item == null)
throw new ArgumentNullException("Item");
int[] order = GetColumnOrder();
if (order == null) // No Columns
return subItemRect;
if (SubItem >= order.Length)
throw new IndexOutOfRangeException("SubItem "+SubItem+" out of range");
// Retrieve the bounds of the entire ListViewItem (all subitems)
Rectangle lviBounds = Item.GetBounds(ItemBoundsPortion.Entire);
int subItemX = lviBounds.Left;
// Calculate the X position of the SubItem.
// Because the columns can be reordered we have to use Columns[order[i]] instead of Columns[i] !
ColumnHeader col;
int i;
for (i=0; i
/// Add a control to the ListView
///
/// Control to be added
/// Index of column
/// Index of row
public void AddEmbeddedControl(Control c, int col, int row)
{
AddEmbeddedControl(c,col,row,DockStyle.Fill);
}
///
/// Add a control to the ListView
///
/// Control to be added
/// Index of column
/// Index of row
/// Location and resize behavior of embedded control
public void AddEmbeddedControl(Control c, int col, int row, DockStyle dock)
{
if (c==null)
throw new ArgumentNullException();
if (col>=Columns.Count || row>=Items.Count)
throw new ArgumentOutOfRangeException();
EmbeddedControl ec;
ec.Control = c;
ec.Column = col;
ec.Row = row;
ec.Dock = dock;
ec.Item = Items[row];
_embeddedControls.Add(ec);
// Add a Click event handler to select the ListView row when an embedded control is clicked
c.Click += new EventHandler(_embeddedControl_Click);
this.Controls.Add(c);
}
///
/// Remove a control from the ListView
///
/// Control to be removed
public void RemoveEmbeddedControl(Control c)
{
if (c == null)
throw new ArgumentNullException();
for (int i=0; i<_embeddedControls.Count; i++)
{
EmbeddedControl ec = (EmbeddedControl)_embeddedControls[i];
if (ec.Control == c)
{
c.Click -= new EventHandler(_embeddedControl_Click);
this.Controls.Remove(c);
_embeddedControls.RemoveAt(i);
return;
}
}
throw new Exception("Control not found!");
}
///
/// Retrieve the control embedded at a given location
///
/// Index of Column
/// Index of Row
/// Control found at given location or null if none assigned.
public Control GetEmbeddedControl(int col, int row)
{
foreach (EmbeddedControl ec in _embeddedControls)
if (ec.Row == row && ec.Column == col)
return ec.Control;
return null;
}
[DefaultValue(View.LargeIcon)]
public new View View
{
get
{
return base.View;
}
set
{
// Embedded controls are rendered only when we're in Details mode
foreach (EmbeddedControl ec in _embeddedControls)
ec.Control.Visible = (value == View.Details);
base.View = value;
}
}
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case WM_PAINT:
if (View != View.Details)
break;
// Calculate the position of all embedded controls
foreach (EmbeddedControl ec in _embeddedControls)
{
Rectangle rc = this.GetSubItemBounds(ec.Item, ec.Column);
if ((this.HeaderStyle != ColumnHeaderStyle.None) &&
(rc.Top