none
ListView 的 Empty Markup 不能与 SetWindowTheme 和 AutoResizeColumns 同时工作 RRS feed

  • 问题

  • 我想对一个 ListView 设定 Empty Markup,就是当 ListView 为空时所显示的文本提示信息。但如果我使用了 SetWindowTheme 或 AutoResizeColumns,这个标记就会消失。这是我的部分代码:

    internal static class ExtensionMethods
    {
        public static void SetDoubleBuffered(this ListView listview, bool value)
        {
            PropertyInfo pi = typeof(ListView).GetProperty("DoubleBuffered", BindingFlags.NonPublic | BindingFlags.Instance);
            pi.SetValue(listview, value);
        }
    
        public static void SetWindowTheme(this ListView listview, string pszSubAppName, string pszSubIdList)
        {
            NativeMethods.SetWindowTheme(listview.Handle, pszSubAppName, pszSubIdList);
        }
    }
    
    internal static class NativeMethods
    {
        public const Int32 WM_NOTIFY = 0x004e;
        public const Int32 WM_LBUTTONDBLCLK = 0x0203;
        public const Int32 WM_USER = 0x0400;
        public const UInt32 LVN_FIRST = unchecked(0u - 100u);
        public const UInt32 LVN_GETEMPTYMARKUP = LVN_FIRST - 87;
        public const Int32 L_MAX_URL_LENGTH = 2084;
    
        [StructLayout(LayoutKind.Sequential)]
        public struct NMHDR
        {
            public IntPtr hwndFrom;
            public IntPtr idFrom;
            public UInt32 code;
        }
    
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public struct NMLVEMPTYMARKUP
        {
            public NMHDR hdr;
            public UInt32 dwFlags;
    
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = L_MAX_URL_LENGTH)]
            public String szMarkup;
        }
    
        [DllImport("uxtheme.dll", CharSet = CharSet.Unicode)]
        public static extern Int32 SetWindowTheme(IntPtr hWnd, String pszSubAppName, String pszSubIdList);
    }
    
    public partial class MainForm : Form
    {
        private ListView listView1 = new ListView();
    
        public MainForm()
        {
            InitializeComponent();
    
            this.Controls.Add(listView1);
    
            listView1.Dock = DockStyle.Fill;
            listView1.View = View.Details;
            listView1.Columns.Add("Test");
    
            listView1.SetDoubleBuffered(true);
    
            // listView1.SetWindowTheme("Explorer", null);
            // listView1.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);
        }
    
        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case NativeMethods.WM_NOTIFY:
                    var nmhdr = (NativeMethods.NMHDR)m.GetLParam(typeof(NativeMethods.NMHDR));
                    switch (nmhdr.code)
                    {
                        case NativeMethods.LVN_GETEMPTYMARKUP:
                            if (Control.FromHandle(nmhdr.hwndFrom) == listView1)
                            {
                                var markup = (NativeMethods.NMLVEMPTYMARKUP)m.GetLParam(typeof(NativeMethods.NMLVEMPTYMARKUP));
                                markup.szMarkup = "This is an empty ListView.";
                                Marshal.StructureToPtr(markup, m.LParam, false);
                                m.Result = new IntPtr(1);
                                return;
                            }
                            break;
                    }
                    break;
            }
            base.WndProc(ref m);
        }
    }

    这个例子可以显示标记,但如果我取消注释下面的任意一行:

            // listView1.SetWindowTheme("Explorer", null);
            // listView1.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);

    这个标记就会消失。

    我已经证实了在 Win32 层次上这个是可以实现的,参见 http://stackoverflow.com/questions/12106631/listviews-empty-markup-cant-work-with-setwindowtheme-and-autoresizecolumns,但不知为何 C# 下就不行。请问该如何解决?

    • 已编辑 EFanZh 2012年8月27日 8:22
    2012年8月27日 6:33

答案

全部回复

  • Hi EFanZh,

      因为你即设置了半透明的主题又想用markup标记,因为markup标记也设置在半透明标记上的,所以你看不到这个This is an empty ListView.因为ListView控件的背景本身就不能设置alpha数值,而markup标记作为半透明的属性本身不能更改,所以你仍然使用半透明主题的话,那么就看不到这个标记的,实际它还在,就像在黑色的背景上显示黑色字体一样是看不见的。

     


    Jason Wang [MSFT]
    MSDN Community Support | Feedback to us

    2012年8月28日 3:53
    版主
  • 我不太明白,什么叫“因为 markup 标记也设置在半透明标记上的,所以你看不到这个 This is an empty ListView”?

    你说的半透明主体是指 SetWindowTheme 所设置的吗?但我可以使用纯 Win32 API 实现半透明 + Markup 这个效果的。

    况且,为什么连 AutoResizeColumns 都不能用?


    EFanZh

    2012年8月28日 4:17
  • 可以将

    listView1.SetWindowTheme("Explorer", null);
    listView1.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);

    放入 Form 的 Load 事件中就行了,原因未知。参见:http://social.msdn.microsoft.com/Forums/en-US/winforms/thread/168c2b98-aefe-4c17-8ffc-cf15485a84ad

    另外,也可重写 OnHandleCreated 方法,在其中执行上两行,原因未知。


    EFanZh

    • 已标记为答案 EFanZh 2012年9月6日 10:47
    2012年9月6日 10:47