C#在Listview中显示文件和文件夹图标

时间:2016-06-13 13:32:45

标签: c# file listview icons directory

我开发了一个像文件浏览器一样的应用程序   有listview显示目录中的文件和子文件夹。

如何在列表视图中显示文件和文件夹图标

以下方式,将文件路径添加到列表视图。我想展示图标:

string[] s = Directory.GetDirectories(file);
        foreach (string file in s)
        {
             listView1.Items.Add(file);

        }

1 个答案:

答案 0 :(得分:9)

有几种不同的方法可以做到这一点。一种方法是创建一个ImageList并将其链接到ListView,然后检索每个文件的图标,将其添加到ImageList,并设置ListViewItem以在ImageList中的相应索引处显示图标。

另一种方法是利用由shell维护的系统映像列表。这样可以避免自己维护图标的重复副本。想象一下,如果ListView中有一堆文件夹。所有这些都将具有相同的图标,但没有一丝特别的关注,您将保存该文件夹图标的多个副本,因为您正在显示使用它的项目。 shell实现会为您处理所有这些重复跟踪。系统映像列表仅包含所需的图标(您明确请求的图标),然后仅包含每个图标的单个副本。我认为这是一个更清洁,更优雅的设计,所以让我们实现它。我们需要一堆P / Invoke代码。

internal static class NativeMethods
{
   public const uint LVM_FIRST = 0x1000;
   public const uint LVM_GETIMAGELIST = (LVM_FIRST + 2);
   public const uint LVM_SETIMAGELIST = (LVM_FIRST + 3);

   public const uint LVSIL_NORMAL      = 0;
   public const uint LVSIL_SMALL       = 1;
   public const uint LVSIL_STATE       = 2;
   public const uint LVSIL_GROUPHEADER = 3;

   [DllImport("user32")]
   public static extern IntPtr SendMessage(IntPtr hWnd,
                                           uint   msg,
                                           uint   wParam,
                                           IntPtr lParam);

   [DllImport("comctl32")]
   public static extern bool ImageList_Destroy(IntPtr hImageList);

   public const uint SHGFI_DISPLAYNAME  = 0x200;
   public const uint SHGFI_ICON         = 0x100;
   public const uint SHGFI_LARGEICON    = 0x0;
   public const uint SHGFI_SMALLICON    = 0x1;
   public const uint SHGFI_SYSICONINDEX = 0x4000;

   [StructLayout(LayoutKind.Sequential)]
   public struct SHFILEINFO
   {
      public IntPtr hIcon;
      public int    iIcon;
      public uint   dwAttributes;
      [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260 /* MAX_PATH */)]
      public string szDisplayName;
      [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
      public string szTypeName;
   };

   [DllImport("shell32")]
   public static extern IntPtr SHGetFileInfo(string         pszPath,
                                             uint           dwFileAttributes,
                                             ref SHFILEINFO psfi,
                                             uint           cbSizeFileInfo,
                                             uint           uFlags);

   [DllImport("uxtheme", CharSet = CharSet.Unicode)]
   public static extern int SetWindowTheme(IntPtr hWnd,
                                           string pszSubAppName,
                                           string pszSubIdList);
}

现在,让我们使用它。出于演示目的,我将一个ListView控件添加到名为listView1的表单中,将其设置为显示在" Details"模式,并将以下代码转储到表单的加载事件处理程序:

private void Form1_Load(object sender, EventArgs e)
{
   // Obtain a handle to the system image list.
   NativeMethods.SHFILEINFO shfi = new NativeMethods.SHFILEINFO();
   IntPtr hSysImgList = NativeMethods.SHGetFileInfo("",
                                                    0,
                                                    ref shfi,
                                                    (uint)Marshal.SizeOf(shfi),
                                                    NativeMethods.SHGFI_SYSICONINDEX
                                                     | NativeMethods.SHGFI_SMALLICON);
   Debug.Assert(hSysImgList != IntPtr.Zero);  // cross our fingers and hope to succeed!

   // Set the ListView control to use that image list.
   IntPtr hOldImgList = NativeMethods.SendMessage(listView1.Handle,
                                                  NativeMethods.LVM_SETIMAGELIST,
                                                  NativeMethods.LVSIL_SMALL,
                                                  hSysImgList);

   // If the ListView control already had an image list, delete the old one.
   if (hOldImgList != IntPtr.Zero)
   {
      NativeMethods.ImageList_Destroy(hOldImgList);
   }

   // Set up the ListView control's basic properties.
   // Put it in "Details" mode, create a column so that "Details" mode will work,
   // and set its theme so it will look like the one used by Explorer.
   listView1.View = View.Details;
   listView1.Columns.Add("Name", 500);
   NativeMethods.SetWindowTheme(listView1.Handle, "Explorer", null);

   // Get the items from the file system, and add each of them to the ListView,
   // complete with their corresponding name and icon indices.
   string[] s = Directory.GetFileSystemEntries(@"C:\...");
   foreach (string file in s)
   {
      IntPtr himl = NativeMethods.SHGetFileInfo(file,
                                                0,
                                                ref shfi,
                                                (uint)Marshal.SizeOf(shfi),
                                                NativeMethods.SHGFI_DISPLAYNAME
                                                  | NativeMethods.SHGFI_SYSICONINDEX
                                                  | NativeMethods.SHGFI_SMALLICON);
      Debug.Assert(himl == hSysImgList); // should be the same imagelist as the one we set
      listView1.Items.Add(shfi.szDisplayName, shfi.iIcon);
   }
}

请注意,作为一个简单的示例程序,这几乎没有错误检查。我投入了一些Debug.Assert健全性检查,只是为了做好准备。

另外,为了完整起见,我继续使用代码使ListView看起来像Explorer使用的那样。这是由SetWindowTheme function处理的。

shell还有其他功能但你会在这里失踪。例如,shell覆盖 - 某些图标上出现的小徽章,例如已经检入源控制系统的徽章。这留给了读者的练习。 (提示:LVSIL_STATE标志用于为ListView控件设置"状态"图像列表。)当然,他们在一天内没有编写资源管理器。