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