ListView空标记文本

时间:2008-11-13 15:45:38

标签: .net winforms listview windows-vista interop

Vista推出了一个新的API,用于在列表视图控件中没有任何项目时显示文本。正如MSDN库所述,我应该处理LVN_GETEMPTYMARKUP通知。

在继承的ListView控件中,WndProc方法被覆盖:

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);
  }
}

然而,它不起作用(虽然它不会抛出任何异常)。实际上我从未得到nmhdr.code等于-187。有什么想法吗?

4 个答案:

答案 0 :(得分:3)

WM_NOTIFY消息不会发送到控件(列表视图),而是发送到父级(表单)。这在Win32世界中是有意义的,因为这些消息对于拦截非常有用,但是对控件进行子类化是非常痛苦的,特别是当你想要在每种情况下都有不同的行为时。使用.NET不再是这种情况。

方便地,标准的.NET消息处理在消息中“反映”消息,以便您可以拦截消息并在控件的WndProc中处理它 - 但反射的消息不再是WM_NOTIFY( 0x004E),而是WM_REFLECT | WM_NOTIFY(0x204E)。

因此,如果您修改WndProc以查找该值,那么它应该可以正常工作。

答案 1 :(得分:0)

您是否尝试在控件上调用SetWindowTheme,如this article

所示

答案 2 :(得分:0)

另一种解决方案(这样你就不必监视WndProc),就是添加一个类似这样的绘图处理程序:

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!
  }
}

那些来自记忆,但你应该明白这一点。

希望有所帮助。

答案 3 :(得分:0)

我自己也很努力。

要使原始问题中的代码生效,请使用[StructLayout(LayoutKind.Sequential,CharSet = CharSet.Unicode)]标记NMLVEMPTYMARKUP结构(CharSet.Unicode很重要)。

此外,在设置标记值后,调用Marshal.StructureToPtr(nmlvemptymarkup,m.LParam,false)将数据复制回LParam指向的缓冲区。