|
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace ListViewEmbeddedControls
{
/// <summary>
/// Zusammenfassung f�r ListViewEx.
/// </summary>
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
/// <summary>
/// Structure to hold an embedded control's info
/// </summary>
private struct EmbeddedControl
{
public Guid ID;
public Control Control;
public DockStyle Dock;
public ListViewItem Item;
public int SubItemIndex;
}
private ArrayList _embeddedControls = new ArrayList();
public ListViewEx() {}
/// <summary>
/// Retrieve the order in which columns appear
/// </summary>
/// <returns>Current display order of column indices</returns>
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;
}
/// <summary>
/// Retrieve the bounds of a ListViewSubItem
/// </summary>
/// <param name="Item">The Item containing the SubItem</param>
/// <param name="SubItem">Index of the SubItem</param>
/// <returns>Subitem's bounds</returns>
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<order.Length; i++)
{
col = this.Columns[order[i]];
if (col.Index == SubItem)
break;
subItemX += col.Width;
}
subItemRect = new Rectangle(subItemX, lviBounds.Top, this.Columns[order[i]].Width, lviBounds.Height);
return subItemRect;
}
/// <summary>
/// Add a control to the ListView
/// </summary>
/// <param name="id">Identifier for subsequent references to the embedded control.</param>
/// <param name="c">Control to be added</param>
/// <param name="item">ListViewItem in which to embed the control.</param>
/// <param name="subItemIndex">The index of the sub-item in which the control is embedded.</param>
public void AddEmbeddedControl(Guid id, Control c, ListViewItem item, int subItemIndex)
{
AddEmbeddedControl(id, c, item, subItemIndex, DockStyle.Fill);
}
/// <summary>
/// Add a control to the ListView
/// </summary>
/// <param name="id">Identifier for subsequent references to the embedded control.</param>
/// <param name="c">Control to be added</param>
/// <param name="item">ListViewItem in which to embed the control.</param>
/// <param name="subItemIndex">The index of the sub-item in which the control is embedded.</param>
/// <param name="dock">Location and resize behavior of embedded control</param>
public void AddEmbeddedControl(Guid id, Control c, ListViewItem item, int subItemIndex, DockStyle dock)
{
if (c==null)
throw new ArgumentNullException();
EmbeddedControl ec;
ec.ID = id;
ec.Control = c;
ec.Dock = dock;
ec.Item = item;
ec.SubItemIndex = subItemIndex;
_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);
}
/// <summary>
/// Remove a control from the ListView
/// </summary>
/// <param name="c">Control to be removed</param>
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!");
}
/// <summary>
/// Retrieve the control embedded at a given location
/// </summary>
/// <param name="col">Index of Column</param>
/// <param name="row">Index of Row</param>
/// <returns>Control found at given location or null if none assigned.</returns>
public Control GetEmbeddedControl(Guid id)
{
foreach (EmbeddedControl ec in _embeddedControls)
if (ec.ID == id)
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.SubItemIndex);
if ((this.HeaderStyle != ColumnHeaderStyle.None) &&
(rc.Top<this.Font.Height)) // Control overlaps ColumnHeader
{
ec.Control.Visible = false;
continue;
}
else
{
ec.Control.Visible = true;
}
switch (ec.Dock)
{
case DockStyle.Fill:
break;
case DockStyle.Top:
rc.Height = ec.Control.Height;
break;
case DockStyle.Left:
rc.Width = ec.Control.Width;
break;
case DockStyle.Bottom:
rc.Offset(0, rc.Height-ec.Control.Height);
rc.Height = ec.Control.Height;
break;
case DockStyle.Right:
rc.Offset(rc.Width-ec.Control.Width, 0);
rc.Width = ec.Control.Width;
break;
case DockStyle.None:
rc.Size = ec.Control.Size;
break;
}
// Set embedded control's bounds
ec.Control.Bounds = rc;
}
break;
}
base.WndProc (ref m);
}
private void _embeddedControl_Click(object sender, EventArgs e)
{
// When a control is clicked the ListViewItem holding it is selected
foreach (EmbeddedControl ec in _embeddedControls)
{
if (ec.Control == (Control)sender)
{
this.SelectedItems.Clear();
ec.Item.Selected = true;
}
}
}
}
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
I got my B.Sc. in Mathematics and Computer Science from Tel Aviv University in 1997. Since then I have developed software in UNIX, Win32 and .NET. I currently live in Haifa.