ListView changing size

  • Thread starter Thread starter Michael C
  • Start date Start date
M

Michael C

Hi all,

I'm looking to determine when the size of a Column is changed in a ListView
in detail view. Is there an event i can wire up to?

Thanks,
Michael C., MCDBA
 
I'm looking to determine when the size of a Column is changed in a
ListView
in detail view. Is there an event i can wire up to?

not directly.

you should create a class that inherits from the ListView and override its
WndProc. inside the WndProc you should catch incoming WM_NOTIFY messages and
check the value of the "code" field in the NMHDR structure. if you get
HDN_BEGINTRACKA or HDN_BEGINTRACKW then you know that the column is beeing
resized by the user. you can even block changes if you need to.

above solution assumes that you are familiar with Win32 stuff - WndProc and
messages. if you have any problems, please send another message to the
newsgroup and I will respond with the actual c# code.

regards,
Wiktor Zychla
 
Hi Wiktor,

I'm a *little* familiar with Win32 API programming in .NET. Mostly network
and database related stuff though. I'd love to see the C# code if you have
it available. Specifically I'd like to throw an event when a column is
re-sized so that I can capture the column width and save it for later use.

Thanks,
Michael C., MCDBA
 
it available. Specifically I'd like to throw an event when a column is
re-sized so that I can capture the column width and save it for later use.

below is an extract from my actual code. as I've said, you can stick to
BeginTrack and EndTrack events. two collections, cNoResize and cNoDrag, can
contain numbers of columns that you do not want the user to resize or drag.

the code will not compile immediately because of attached win32 specific
consts and structs at the end that you have to put in another class. note
also that this is unsafe code.

put a note in the newsgroup if you still have problems. put a note also if
you succeed.

Regards
Wiktor Zychla

namespace Controls
{
public class ListView_0Class : System.Windows.Forms.ListView
{

public delegate void ListViewHeaderNotifEventHandler( object sender,
ListViewHeaderNotifEventArgs e );

[Category("Behavior")]
public event ListViewHeaderNotifEventHandler BeginDrag;
[Category("Behavior")]
public event ListViewHeaderNotifEventHandler BeginTrack;

[Category("Behavior")]
public event ListViewHeaderNotifEventHandler EndDrag;
[Category("Behavior")]
public event ListViewHeaderNotifEventHandler EndTrack;

public ArrayList cNoResize = new ArrayList();
public ArrayList cNoDrag = new ArrayList();

public ListView_0Class() {}

protected override void OnPaintBackground( PaintEventArgs e )
{
}

unsafe protected override void WndProc( ref Message m )
{
HDITEM hditem;
NMHDR nm;
NMHEADER nmheader;

switch ( m.Msg )
{
case (int)Msg.WM_NOTIFY:

nm = (NMHDR) m.GetLParam(typeof(NMHDR));
switch(nm.code)
{
case (int)HeaderControlNotifications.HDN_BEGINTRACKA:
case (int)HeaderControlNotifications.HDN_BEGINTRACKW:

nmheader = (NMHEADER)m.GetLParam(typeof(NMHEADER));
if ( cNoResize.Contains( nmheader.iItem ) )
{
m.Result = (IntPtr)Convert.ToInt32(true);
return;
}
else if ( BeginTrack != null )
BeginTrack( this, new ListViewHeaderNotifEventArgs(
nmheader.iItem ) );
break;

case (int)HeaderControlNotifications.HDN_BEGINDRAG:

nmheader = (NMHEADER)m.GetLParam(typeof(NMHEADER));
if ( cNoDrag.Contains( nmheader.iItem ) )
{
m.Result = (IntPtr)Convert.ToInt32(true);
return;
}
else if ( BeginDrag != null )
BeginDrag( this, new ListViewHeaderNotifEventArgs(
nmheader.iItem ) );
break;

case (int)HeaderControlNotifications.HDN_ENDTRACKA:
case (int)HeaderControlNotifications.HDN_ENDTRACKW:

nmheader = (NMHEADER)m.GetLParam(typeof(NMHEADER));
if ( EndTrack != null )
EndTrack( this, new ListViewHeaderNotifEventArgs(
nmheader.iItem ) );
break;

case (int)HeaderControlNotifications.HDN_ENDDRAG:

nmheader = (NMHEADER)m.GetLParam(typeof(NMHEADER));
hditem = *((HDITEM*)nmheader.pItem.ToPointer());

if ( cNoDrag.Contains( hditem.iOrder ) )
{
m.Result = (IntPtr)Convert.ToInt32(true);
return;
}
else if ( EndDrag != null )
EndDrag( this, new ListViewHeaderNotifEventArgs( nmheader.iItem ) );
break;

default:
break;
}
break;
}
base.WndProc( ref m );
} // end void WndProc

} // end class

public class ListViewHeaderNotifEventArgs : EventArgs
{
public ListViewHeaderNotifEventArgs( int iColumn )
{
this.iColumn = iColumn;
}
public int iColumn;
}
}


[StructLayout(LayoutKind.Sequential)]
public struct NMHDR
{
public IntPtr hwndFrom;
public int idFrom;
public int code;
}
#endregion

// NMHEADER
#region
[StructLayout(LayoutKind.Sequential)]
public struct NMHEADER
{
public NMHDR hdr;
public int iItem;
public int iButton;
public IntPtr pItem;
}
#endregion

// HDITEM
#region
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
public struct HDITEM
{
public uint mask;
public int cxy;
public IntPtr pszText;
public IntPtr hbm;
public int cchTextMax;
public int fmt;
public int lParam;
public int iImage;
public int iOrder;
}
#endregion

// Header Control Notifications
#region
public enum HeaderControlNotifications
{
HDN_FIRST = (0-300),
HDN_BEGINTRACKA = (HDN_FIRST-6),
HDN_ENDTRACKA = (HDN_FIRST-7),
HDN_BEGINTRACKW = (HDN_FIRST-26),
HDN_ENDTRACKW = (HDN_FIRST-27),
HDN_ITEMCLICKW = (HDN_FIRST-22),
HDN_BEGINDRAG = (HDN_FIRST-10),
HDN_ENDDRAG = (HDN_FIRST-11),
}
#endregion
 
Thanks Wiktor! Excellent code, it works great! The only thing I had to
change was adding a const definition for WM_NOTIFY. Other than that, it's
very efficient and works a lot better than my previous solution!

Thanks!

Michael C., MCDBA

Wiktor Zychla said:
it available. Specifically I'd like to throw an event when a column is
re-sized so that I can capture the column width and save it for later use.

below is an extract from my actual code. as I've said, you can stick to
BeginTrack and EndTrack events. two collections, cNoResize and cNoDrag, can
contain numbers of columns that you do not want the user to resize or drag.

the code will not compile immediately because of attached win32 specific
consts and structs at the end that you have to put in another class. note
also that this is unsafe code.

put a note in the newsgroup if you still have problems. put a note also if
you succeed.

Regards
Wiktor Zychla

namespace Controls
{
public class ListView_0Class : System.Windows.Forms.ListView
{

public delegate void ListViewHeaderNotifEventHandler( object sender,
ListViewHeaderNotifEventArgs e );

[Category("Behavior")]
public event ListViewHeaderNotifEventHandler BeginDrag;
[Category("Behavior")]
public event ListViewHeaderNotifEventHandler BeginTrack;

[Category("Behavior")]
public event ListViewHeaderNotifEventHandler EndDrag;
[Category("Behavior")]
public event ListViewHeaderNotifEventHandler EndTrack;

public ArrayList cNoResize = new ArrayList();
public ArrayList cNoDrag = new ArrayList();

public ListView_0Class() {}

protected override void OnPaintBackground( PaintEventArgs e )
{
}

unsafe protected override void WndProc( ref Message m )
{
HDITEM hditem;
NMHDR nm;
NMHEADER nmheader;

switch ( m.Msg )
{
case (int)Msg.WM_NOTIFY:

nm = (NMHDR) m.GetLParam(typeof(NMHDR));
switch(nm.code)
{
case (int)HeaderControlNotifications.HDN_BEGINTRACKA:
case (int)HeaderControlNotifications.HDN_BEGINTRACKW:

nmheader = (NMHEADER)m.GetLParam(typeof(NMHEADER));
if ( cNoResize.Contains( nmheader.iItem ) )
{
m.Result = (IntPtr)Convert.ToInt32(true);
return;
}
else if ( BeginTrack != null )
BeginTrack( this, new ListViewHeaderNotifEventArgs(
nmheader.iItem ) );
break;

case (int)HeaderControlNotifications.HDN_BEGINDRAG:

nmheader = (NMHEADER)m.GetLParam(typeof(NMHEADER));
if ( cNoDrag.Contains( nmheader.iItem ) )
{
m.Result = (IntPtr)Convert.ToInt32(true);
return;
}
else if ( BeginDrag != null )
BeginDrag( this, new ListViewHeaderNotifEventArgs(
nmheader.iItem ) );
break;

case (int)HeaderControlNotifications.HDN_ENDTRACKA:
case (int)HeaderControlNotifications.HDN_ENDTRACKW:

nmheader = (NMHEADER)m.GetLParam(typeof(NMHEADER));
if ( EndTrack != null )
EndTrack( this, new ListViewHeaderNotifEventArgs(
nmheader.iItem ) );
break;

case (int)HeaderControlNotifications.HDN_ENDDRAG:

nmheader = (NMHEADER)m.GetLParam(typeof(NMHEADER));
hditem = *((HDITEM*)nmheader.pItem.ToPointer());

if ( cNoDrag.Contains( hditem.iOrder ) )
{
m.Result = (IntPtr)Convert.ToInt32(true);
return;
}
else if ( EndDrag != null )
EndDrag( this, new ListViewHeaderNotifEventArgs( nmheader.iItem ) );
break;

default:
break;
}
break;
}
base.WndProc( ref m );
} // end void WndProc

} // end class

public class ListViewHeaderNotifEventArgs : EventArgs
{
public ListViewHeaderNotifEventArgs( int iColumn )
{
this.iColumn = iColumn;
}
public int iColumn;
}
}


[StructLayout(LayoutKind.Sequential)]
public struct NMHDR
{
public IntPtr hwndFrom;
public int idFrom;
public int code;
}
#endregion

// NMHEADER
#region
[StructLayout(LayoutKind.Sequential)]
public struct NMHEADER
{
public NMHDR hdr;
public int iItem;
public int iButton;
public IntPtr pItem;
}
#endregion

// HDITEM
#region
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
public struct HDITEM
{
public uint mask;
public int cxy;
public IntPtr pszText;
public IntPtr hbm;
public int cchTextMax;
public int fmt;
public int lParam;
public int iImage;
public int iOrder;
}
#endregion

// Header Control Notifications
#region
public enum HeaderControlNotifications
{
HDN_FIRST = (0-300),
HDN_BEGINTRACKA = (HDN_FIRST-6),
HDN_ENDTRACKA = (HDN_FIRST-7),
HDN_BEGINTRACKW = (HDN_FIRST-26),
HDN_ENDTRACKW = (HDN_FIRST-27),
HDN_ITEMCLICKW = (HDN_FIRST-22),
HDN_BEGINDRAG = (HDN_FIRST-10),
HDN_ENDDRAG = (HDN_FIRST-11),
}
#endregion
 
I am interested in using the code that you wrote in the previous post;
however, I think there is a problem. The line
case (int)Msg.WM_NOTIFY:

in the WndProc override won't compile. What is Msg?

Thanks for your help.
Pat

Wiktor said:
it available. Specifically I'd like to throw an event when a column is
re-sized so that I can capture the column width and save it for later use.

below is an extract from my actual code. as I've said, you can stick to
BeginTrack and EndTrack events. two collections, cNoResize and cNoDrag, can
contain numbers of columns that you do not want the user to resize or drag.

the code will not compile immediately because of attached win32 specific
consts and structs at the end that you have to put in another class. note
also that this is unsafe code.

put a note in the newsgroup if you still have problems. put a note also if
you succeed.

Regards
Wiktor Zychla

namespace Controls
{
public class ListView_0Class : System.Windows.Forms.ListView
{

public delegate void ListViewHeaderNotifEventHandler( object sender,
ListViewHeaderNotifEventArgs e );

[Category("Behavior")]
public event ListViewHeaderNotifEventHandler BeginDrag;
[Category("Behavior")]
public event ListViewHeaderNotifEventHandler BeginTrack;

[Category("Behavior")]
public event ListViewHeaderNotifEventHandler EndDrag;
[Category("Behavior")]
public event ListViewHeaderNotifEventHandler EndTrack;

public ArrayList cNoResize = new ArrayList();
public ArrayList cNoDrag = new ArrayList();

public ListView_0Class() {}

protected override void OnPaintBackground( PaintEventArgs e )
{
}

unsafe protected override void WndProc( ref Message m )
{
HDITEM hditem;
NMHDR nm;
NMHEADER nmheader;

switch ( m.Msg )
{
case (int)Msg.WM_NOTIFY:

nm = (NMHDR) m.GetLParam(typeof(NMHDR));
switch(nm.code)
{
case (int)HeaderControlNotifications.HDN_BEGINTRACKA:
case (int)HeaderControlNotifications.HDN_BEGINTRACKW:

nmheader = (NMHEADER)m.GetLParam(typeof(NMHEADER));
if ( cNoResize.Contains( nmheader.iItem ) )
{
m.Result = (IntPtr)Convert.ToInt32(true);
return;
}
else if ( BeginTrack != null )
BeginTrack( this, new ListViewHeaderNotifEventArgs(
nmheader.iItem ) );
break;

case (int)HeaderControlNotifications.HDN_BEGINDRAG:

nmheader = (NMHEADER)m.GetLParam(typeof(NMHEADER));
if ( cNoDrag.Contains( nmheader.iItem ) )
{
m.Result = (IntPtr)Convert.ToInt32(true);
return;
}
else if ( BeginDrag != null )
BeginDrag( this, new ListViewHeaderNotifEventArgs(
nmheader.iItem ) );
break;

case (int)HeaderControlNotifications.HDN_ENDTRACKA:
case (int)HeaderControlNotifications.HDN_ENDTRACKW:

nmheader = (NMHEADER)m.GetLParam(typeof(NMHEADER));
if ( EndTrack != null )
EndTrack( this, new ListViewHeaderNotifEventArgs(
nmheader.iItem ) );
break;

case (int)HeaderControlNotifications.HDN_ENDDRAG:

nmheader = (NMHEADER)m.GetLParam(typeof(NMHEADER));
hditem = *((HDITEM*)nmheader.pItem.ToPointer());

if ( cNoDrag.Contains( hditem.iOrder ) )
{
m.Result = (IntPtr)Convert.ToInt32(true);
return;
}
else if ( EndDrag != null )
EndDrag( this, new ListViewHeaderNotifEventArgs( nmheader.iItem ) );
break;

default:
break;
}
break;
}
base.WndProc( ref m );
} // end void WndProc

} // end class

public class ListViewHeaderNotifEventArgs : EventArgs
{
public ListViewHeaderNotifEventArgs( int iColumn )
{
this.iColumn = iColumn;
}
public int iColumn;
}
}


[StructLayout(LayoutKind.Sequential)]
public struct NMHDR
{
public IntPtr hwndFrom;
public int idFrom;
public int code;
}
#endregion

// NMHEADER
#region
[StructLayout(LayoutKind.Sequential)]
public struct NMHEADER
{
public NMHDR hdr;
public int iItem;
public int iButton;
public IntPtr pItem;
}
#endregion

// HDITEM
#region
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
public struct HDITEM
{
public uint mask;
public int cxy;
public IntPtr pszText;
public IntPtr hbm;
public int cchTextMax;
public int fmt;
public int lParam;
public int iImage;
public int iOrder;
}
#endregion

// Header Control Notifications
#region
public enum HeaderControlNotifications
{
HDN_FIRST = (0-300),
HDN_BEGINTRACKA = (HDN_FIRST-6),
HDN_ENDTRACKA = (HDN_FIRST-7),
HDN_BEGINTRACKW = (HDN_FIRST-26),
HDN_ENDTRACKW = (HDN_FIRST-27),
HDN_ITEMCLICKW = (HDN_FIRST-22),
HDN_BEGINDRAG = (HDN_FIRST-10),
HDN_ENDDRAG = (HDN_FIRST-11),
}
#endregion
 
Back
Top