2016-06-13 2 views
2

Je développe une application qui fonctionne comme un explorateur de fichiers.
Il existe un listview qui affiche les fichiers et sous-dossiers d'un répertoire.C# Afficher les icônes de fichiers et de dossiers dans la vue de liste

Comment afficher les fichiers et dossiers icônes dans listview?

De la manière suivante, ajoute le chemin du fichier à la liste. Je voudrais montrer des icônes:

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

     } 
+0

https://msdn.microsoft.com/en-us/library/ms404308(v=vs.110).aspx? – BugFinder

+0

Une question * extrêmement * large. Voulez-vous que nous vous apprenions comment définir une icône pour un élément dans un LIstView? Voulez-vous que nous vous apprenions comment récupérer la liste d'images du système? Ou voulez-vous récupérer l'icône pour chaque fichier individuel? Quelle icône de taille voulez-vous, grande ou petite? –

+0

@CodyGray, je voudrais représenter chaque fichier et dossier avec l'icône appropriée, de petites icônes. Merci. – user3165438

Répondre

4

Il y a plusieurs manières différentes de faire ceci. L'one-way est de créer un ImageList et liez-le à votre ListView, puis récupérez l'icône pour chaque fichier individuel, ajoutez-le à votre ImageList, et placez le ListViewItem pour montrer l'icône à l'index approprié dans votre ImageList. Une autre solution serait de tirer parti de la liste d'images système, qui est gérée par l'interpréteur de commandes. Cela éviterait de devoir conserver vous-même des copies des icônes. Imaginez si vous avez un tas de dossiers dans votre ListView. Tous auront la même icône, mais sans un soin particulier, vous enregistreriez autant de copies de l'icône de ce dossier que vous affichez les éléments qui l'utilisent. L'implémentation de l'interpréteur de commandes prend en charge tout ce suivi en double pour vous. La liste d'images système ne contient que les icônes nécessaires (celles que vous demandez explicitement) et ne contient qu'une seule copie de chacune d'elles. Je pense que c'est un design plus propre et plus élégant, alors mettons-le en place. Nous aurons besoin d'un tas de code 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); 
} 

Et maintenant, utilisons-le. Pour des fins de démonstration, j'ai ajouté un contrôle ListView à une forme, nommée listView1, réglez-le à afficher en mode « Détails », et largué le code suivant dans le gestionnaire d'événements Load du formulaire:

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

Notez que, comme programme d'exemple simple, cela fait peu ou pas de vérification d'erreur. J'ai jeté quelques contrôles de santé mentale Debug.Assert juste pour faire bonne mesure.

Aussi, par souci d'exhaustivité, je suis allé de l'avant et ai jeté du code pour faire ressembler le ListView à celui qu'utilise Explorer. C'est géré par le SetWindowTheme function.

Il y a d'autres choses que le shell fait, mais que vous allez manquer ici. Par exemple, les superpositions de coquilles, les petits badges qui apparaissent sur certaines icônes, comme celles qui ont été vérifiées dans un système de contrôle de source. C'est laissé comme un exercice pour le lecteur. (Astuce: l'indicateur LVSIL_STATE est utilisé pour définir une liste d'images "d'état" pour un contrôle ListView.) Ils n'ont pas écrit Explorer en un jour, bien sûr.

+0

Merci pour le temps et les efforts. J'ai cahecked votre réponse comme acceptée avant même de l'essayer encore. Une dernière chose: pouvez-vous montrer le raccourci que vous avez mentionné au début: utiliser l'imageList? Merci d'avance! – user3165438

+0

@user Ce n'est pas vraiment plus court de cette façon ... La plupart du code est le même, en fait. Je peux l'ajouter à ma réponse si vous le voulez vraiment, mais en fait, vous créez un objet ImageList et vous l'attribuez normalement à votre ListView.Ensuite, à l'intérieur de la boucle foreach, vous appelez la fonction 'NativeMethods.SHGetFileInfo' avec les indicateurs' SHGFI_ICON' et 'SHGFI_SMALLICON'. Cela remplira le membre 'shfi.hIcon'. Vous utilisez cela pour créer une icône ('Icon.FromHandle (shfi.hIcon)'), ajoutez l'objet Icon résultant à votre objet ImageList, et finalement supprimez 'shfi.hIcon' par P/Invoke' DestroyIcon' (pour éviter les fuites) . –

+0

Fondamentalement, la différence est, d'une manière que vous obtenez la liste d'images du système une fois, puis les appels suivants à 'SHGetFileInfo' vous renverra l'index de l'icône dans cette liste d'images. Dans l'autre sens, vous gérez vous-même la liste d'images, en appelant 'SHGetFileInfo' pour obtenir un handle de l'icône actuelle, que vous devrez ajouter à votre liste d'images autogérées. –