views:

562

answers:

4

Vista has introduced a new API to display a text in the list view control when it doesn't have any items. As the MSDN library states, I should process the LVN_GETEMPTYMARKUP notification.

In the inherited ListView control the WndProc method is overriden:

protected override void WndProc(ref Message m) {
  try {
    if(m.Msg == 78 /* WM_NOTIFY */) {
      var nmhdr = (NMHDR)Marshal.PtrToStructure(m.LParam, typeof(NMHDR));
      if(nmhdr.code == -187 /* LVN_GETEMPTYMARKUP */) {
        var nmlvemptymarkup =
          (NMLVEMPTYMARKUP)Marshal.PtrToStructure(m.LParam, typeof(NMLVEMPTYMARKUP));
        nmlvemptymarkup.szMarkup = "The ListView is empty.";
        m.Result = (IntPtr)1;
      }
    }
  } finally {
    base.WndProc(ref m);
  }
}

However, it doesn't work (although it doesn't throw any exception). Actually I never get nmhdr.code equals to -187. Any ideas?

A: 

Have you tried calling SetWindowTheme on the control, as indicated in this article?

Sunlight
Set to "explorer".
Michael Damatov
A: 

An alternative solution (so that you don't have to monitor the WndProc), would be to add a paint handler something like this:

listview_onPaint(object sender, eventargs e)
{
  if ( listview.items.count <= 0 )
  {
     e.graphics.drawstring("The Listview is empty"); //put all the proper args in here!
  }
}

thats from memory, but you should get the idea.

hope thats of some help.

Pondidum
A: 

WM_NOTIFY messages are not sent to the control (the listview), but rather to the parent (the form). This made sense in the Win32 world because these messages are very useful to intercept but it was moderately painful to subclass the control, especially when you wanted different behaviour in each case. With .NET that's no longer the case.

Conveniently, the standard .NET message processing "reflects" the message back at the control, so that you can intercept the message and handle it within the control's WndProc -- but the reflected message is no longer WM_NOTIFY (0x004E), but rather WM_REFLECT|WM_NOTIFY (0x204E).

So if you modify your WndProc to look for that value instead then it should work.

Miral
A: 

I struggled a lot with this one myself.

To get the code in the original question to work, mark the NMLVEMPTYMARKUP struct with [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] (the CharSet.Unicode is important).

Also, after setting the markup-values, call Marshal.StructureToPtr(nmlvemptymarkup, m.LParam, false) to copy the data back to the buffer pointed to by LParam.

Rune