ListView DrawItem/MeasureItem frustrations

  • Thread starter Thread starter chris s.
  • Start date Start date
C

chris s.

I'm trying to get DrawItem and MeasureItem working on a ListView, with
a view to drawing items in LargeIcon view. I've managed to get
DrawItem working okay, using the code below. My problem is with the
MeasureItem event. The event is only ever called once, and most
annoyingly, are never called when the view isn't the details view.

I've tinkered about with the owner-drawn listview projects on
codeproject.com, and have discovered you need to handle ITEMPREPAINT
for non-details view listviews. The problem with this is, MeasureItem
isn't supported (or rather, I don't know how to handle it), and so you
end up having to handle or Mouse events yourself.

This removes the point of the control being derived from ListView - to
utilise all the functionality a listview has in.

I also tried creating ListViewItemCollections and ListViewItems
myself, but gave up with that as I was getting nowhere.

Hopefully you've read to this stage and haven't dropped off. If anyone
can suggest controls (commercial/free), websites, FAQs etc. that'd be
appreciated.


Cheers
...................................................
The code:
<pre>
// Majority of this is a merger of UtilityLibrary and google groups
examples
public class MyListView : ListView
{
private struct MEASUREITEMSTRUCT
{
public int CtlType;
public int CtlID;
public int itemID;
public int itemWidth;
public int itemHeight;
public IntPtr itemData;
}

[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}

private struct DrawItemStruct
{
public int ctlType;
public int ctlID;
public int itemID;
public int itemAction;
public int itemState;
public IntPtr hWndItem;
public IntPtr hDC;
public RECT rcItem;
public IntPtr itemData;
}

private enum ReflectedMessages
{
OCM__BASE = (0x0400 + 0x1c00),
OCM_DRAWITEM = (OCM__BASE + 0x002B),
}

public event System.Windows.Forms.DrawItemEventHandler DrawItem;
public event MeasureItemEventHandler MeasureItem;
public const int LVS_OWNERDRAWFIXED = 0x0400;
private DrawMode drawMode;

public MyListView()
{
this.drawMode = DrawMode.Normal;
}

protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.Style |= (drawMode != DrawMode.Normal) ? LVS_OWNERDRAWFIXED : 0;
return cp;
}
}

public virtual DrawMode DrawMode
{
get { return drawMode; }
set { drawMode = value; }
}

protected virtual void
OnDrawItem(System.Windows.Forms.DrawItemEventArgs e)
{

}

public virtual void OnMeasureItem(MeasureItemEventArgs e)
{

}

protected override void WndProc(ref System.Windows.Forms.Message m)
{
base.WndProc(ref m);

switch (m.Msg)
{
case (int)ReflectedMessages.OCM_DRAWITEM:
{
DrawItemStruct dis =
(DrawItemStruct)m.GetLParam(typeof(DrawItemStruct));

Graphics graph = Graphics.FromHdc(dis.hDC);
Rectangle rect = new
Rectangle(dis.rcItem.left,dis.rcItem.top,dis.rcItem.right -
dis.rcItem.left,dis.rcItem.bottom - dis.rcItem.top);
int index = dis.itemID;
DrawItemState state = DrawItemState.None;

System.Windows.Forms.DrawItemEventArgs e = new
System.Windows.Forms.DrawItemEventArgs(graph, Font, rect, index,
state, ForeColor, BackColor);
if ( this.DrawItem != null )
{
this.DrawItem(this,e);
}
OnDrawItem(e);

graph.Dispose();
break;
}

case 8236:
this.WmReflectMeasureItem(ref m);
break;

}
}

private void WmReflectMeasureItem(ref Message m)
{
Graphics graphics1;
MeasureItemEventArgs args1;
MEASUREITEMSTRUCT measureitemstruct1 = (MEASUREITEMSTRUCT)
m.GetLParam( typeof(MEASUREITEMSTRUCT) );
if ((this.drawMode == DrawMode.OwnerDrawVariable) &&
(measureitemstruct1.itemID >= 0))
{
graphics1 = Graphics.FromHwnd(this.Handle);
args1 = new MeasureItemEventArgs(graphics1,
measureitemstruct1.itemID, 20);
try
{
if ( this.MeasureItem != null )
{
this.MeasureItem(this,args1);
}
this.OnMeasureItem(args1);
measureitemstruct1.itemHeight = args1.ItemHeight;
}
finally
{
graphics1.Dispose();
}
}

measureitemstruct1.itemHeight = 20;//this.ItemHeight;
Marshal.StructureToPtr(measureitemstruct1, m.LParam, false);
m.Result = ((IntPtr) 1);
}
}
</pre>
 
The docs for LVS_OWNERDRAWFIXED states that
"The owner window can paint items in report view". To me,
this means that it is not supported in any other view.

As for the ITEMPREPAINT constant I can't find that in the docs.
Do you perhaps mean CDDS_ITEMPREPAINT? If so that
is part of _Custom Draw_, which is not the same thing as owner
draw. See the docs for more info on that (NM_CUSTOMDRAW etc.)

What do you want to do with MeasureItem?
(Perhaps there is some other way of solving your problem)

/claes

chris s. said:
I'm trying to get DrawItem and MeasureItem working on a ListView, with
a view to drawing items in LargeIcon view. I've managed to get
DrawItem working okay, using the code below. My problem is with the
MeasureItem event. The event is only ever called once, and most
annoyingly, are never called when the view isn't the details view.

I've tinkered about with the owner-drawn listview projects on
codeproject.com, and have discovered you need to handle ITEMPREPAINT
for non-details view listviews. The problem with this is, MeasureItem
isn't supported (or rather, I don't know how to handle it), and so you
end up having to handle or Mouse events yourself.

This removes the point of the control being derived from ListView - to
utilise all the functionality a listview has in.

I also tried creating ListViewItemCollections and ListViewItems
myself, but gave up with that as I was getting nowhere.

Hopefully you've read to this stage and haven't dropped off. If anyone
can suggest controls (commercial/free), websites, FAQs etc. that'd be
appreciated.


Cheers
..................................................
The code:
<pre>
// Majority of this is a merger of UtilityLibrary and google groups
examples
public class MyListView : ListView
{
private struct MEASUREITEMSTRUCT
{
public int CtlType;
public int CtlID;
public int itemID;
public int itemWidth;
public int itemHeight;
public IntPtr itemData;
}

[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}

private struct DrawItemStruct
{
public int ctlType;
public int ctlID;
public int itemID;
public int itemAction;
public int itemState;
public IntPtr hWndItem;
public IntPtr hDC;
public RECT rcItem;
public IntPtr itemData;
}

private enum ReflectedMessages
{
OCM__BASE = (0x0400 + 0x1c00),
OCM_DRAWITEM = (OCM__BASE + 0x002B),
}

public event System.Windows.Forms.DrawItemEventHandler DrawItem;
public event MeasureItemEventHandler MeasureItem;
public const int LVS_OWNERDRAWFIXED = 0x0400;
private DrawMode drawMode;

public MyListView()
{
this.drawMode = DrawMode.Normal;
}

protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.Style |= (drawMode != DrawMode.Normal) ? LVS_OWNERDRAWFIXED : 0;
return cp;
}
}

public virtual DrawMode DrawMode
{
get { return drawMode; }
set { drawMode = value; }
}

protected virtual void
OnDrawItem(System.Windows.Forms.DrawItemEventArgs e)
{

}

public virtual void OnMeasureItem(MeasureItemEventArgs e)
{

}

protected override void WndProc(ref System.Windows.Forms.Message m)
{
base.WndProc(ref m);

switch (m.Msg)
{
case (int)ReflectedMessages.OCM_DRAWITEM:
{
DrawItemStruct dis =
(DrawItemStruct)m.GetLParam(typeof(DrawItemStruct));

Graphics graph = Graphics.FromHdc(dis.hDC);
Rectangle rect = new
Rectangle(dis.rcItem.left,dis.rcItem.top,dis.rcItem.right -
dis.rcItem.left,dis.rcItem.bottom - dis.rcItem.top);
int index = dis.itemID;
DrawItemState state = DrawItemState.None;

System.Windows.Forms.DrawItemEventArgs e = new
System.Windows.Forms.DrawItemEventArgs(graph, Font, rect, index,
state, ForeColor, BackColor);
if ( this.DrawItem != null )
{
this.DrawItem(this,e);
}
OnDrawItem(e);

graph.Dispose();
break;
}

case 8236:
this.WmReflectMeasureItem(ref m);
break;

}
}

private void WmReflectMeasureItem(ref Message m)
{
Graphics graphics1;
MeasureItemEventArgs args1;
MEASUREITEMSTRUCT measureitemstruct1 = (MEASUREITEMSTRUCT)
m.GetLParam( typeof(MEASUREITEMSTRUCT) );
if ((this.drawMode == DrawMode.OwnerDrawVariable) &&
(measureitemstruct1.itemID >= 0))
{
graphics1 = Graphics.FromHwnd(this.Handle);
args1 = new MeasureItemEventArgs(graphics1,
measureitemstruct1.itemID, 20);
try
{
if ( this.MeasureItem != null )
{
this.MeasureItem(this,args1);
}
this.OnMeasureItem(args1);
measureitemstruct1.itemHeight = args1.ItemHeight;
}
finally
{
graphics1.Dispose();
}
}

measureitemstruct1.itemHeight = 20;//this.ItemHeight;
Marshal.StructureToPtr(measureitemstruct1, m.LParam, false);
m.Result = ((IntPtr) 1);
}
}
</pre>
 
take a look at windowsforms.net and the "new sample applications" look
at something called FotoVision. i know that it is written in VB, but it
implements "custom draw", which by the way, i'm still not sure what that
is. so good luck.

http://www.windowsforms.net/Applications/application.aspx?PageID=50&tabindex=9

etan bukiet

I'm trying to get DrawItem and MeasureItem working on a ListView, with
a view to drawing items in LargeIcon view. I've managed to get
DrawItem working okay, using the code below. My problem is with the
MeasureItem event. The event is only ever called once, and most
annoyingly, are never called when the view isn't the details view.

I've tinkered about with the owner-drawn listview projects on
codeproject.com, and have discovered you need to handle ITEMPREPAINT
for non-details view listviews. The problem with this is, MeasureItem
isn't supported (or rather, I don't know how to handle it), and so you
end up having to handle or Mouse events yourself.

This removes the point of the control being derived from ListView - to
utilise all the functionality a listview has in.

I also tried creating ListViewItemCollections and ListViewItems
myself, but gave up with that as I was getting nowhere.

Hopefully you've read to this stage and haven't dropped off. If anyone
can suggest controls (commercial/free), websites, FAQs etc. that'd be
appreciated.


Cheers
..................................................
The code:
<pre>
// Majority of this is a merger of UtilityLibrary and google groups
examples
public class MyListView : ListView
{
private struct MEASUREITEMSTRUCT
{
public int CtlType;
public int CtlID;
public int itemID;
public int itemWidth;
public int itemHeight;
public IntPtr itemData;
}

[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}

private struct DrawItemStruct
{
public int ctlType;
public int ctlID;
public int itemID;
public int itemAction;
public int itemState;
public IntPtr hWndItem;
public IntPtr hDC;
public RECT rcItem;
public IntPtr itemData;
}

private enum ReflectedMessages
{
OCM__BASE = (0x0400 + 0x1c00),
OCM_DRAWITEM = (OCM__BASE + 0x002B),
}

public event System.Windows.Forms.DrawItemEventHandler DrawItem;
public event MeasureItemEventHandler MeasureItem;
public const int LVS_OWNERDRAWFIXED = 0x0400;
private DrawMode drawMode;

public MyListView()
{
this.drawMode = DrawMode.Normal;
}

protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.Style |= (drawMode != DrawMode.Normal) ? LVS_OWNERDRAWFIXED : 0;
return cp;
}
}

public virtual DrawMode DrawMode
{
get { return drawMode; }
set { drawMode = value; }
}

protected virtual void
OnDrawItem(System.Windows.Forms.DrawItemEventArgs e)
{

}

public virtual void OnMeasureItem(MeasureItemEventArgs e)
{

}

protected override void WndProc(ref System.Windows.Forms.Message m)
{
base.WndProc(ref m);

switch (m.Msg)
{
case (int)ReflectedMessages.OCM_DRAWITEM:
{
DrawItemStruct dis =
(DrawItemStruct)m.GetLParam(typeof(DrawItemStruct));

Graphics graph = Graphics.FromHdc(dis.hDC);
Rectangle rect = new
Rectangle(dis.rcItem.left,dis.rcItem.top,dis.rcItem.right -
dis.rcItem.left,dis.rcItem.bottom - dis.rcItem.top);
int index = dis.itemID;
DrawItemState state = DrawItemState.None;

System.Windows.Forms.DrawItemEventArgs e = new
System.Windows.Forms.DrawItemEventArgs(graph, Font, rect, index,
state, ForeColor, BackColor);
if ( this.DrawItem != null )
{
this.DrawItem(this,e);
}
OnDrawItem(e);

graph.Dispose();
break;
}

case 8236:
this.WmReflectMeasureItem(ref m);
break;

}
}

private void WmReflectMeasureItem(ref Message m)
{
Graphics graphics1;
MeasureItemEventArgs args1;
MEASUREITEMSTRUCT measureitemstruct1 = (MEASUREITEMSTRUCT)
m.GetLParam( typeof(MEASUREITEMSTRUCT) );
if ((this.drawMode == DrawMode.OwnerDrawVariable) &&
(measureitemstruct1.itemID >= 0))
{
graphics1 = Graphics.FromHwnd(this.Handle);
args1 = new MeasureItemEventArgs(graphics1,
measureitemstruct1.itemID, 20);
try
{
if ( this.MeasureItem != null )
{
this.MeasureItem(this,args1);
}
this.OnMeasureItem(args1);
measureitemstruct1.itemHeight = args1.ItemHeight;
}
finally
{
graphics1.Dispose();
}
}

measureitemstruct1.itemHeight = 20;//this.ItemHeight;
Marshal.StructureToPtr(measureitemstruct1, m.LParam, false);
m.Result = ((IntPtr) 1);
}
}
</pre>
 
Back
Top