Mini Explorador 3 – Obtener el icono de un archivo y pintarlo en cada Nodo


Para mejorar aún más las cosas, vamos a obtener el icono de cada archivo y luego vamos a asignarlo al nodo correspondiente.

El control Treeview permite asignar una imagen a cada nodo, para hacerlo se debe asignar a la propiedad ImageList del TreeView, un control ImageList, donde vamos a tener las imágenes guardadas, después basta con asignar a la propiedad ImageIndex del Nodo, el número que corresponde a la imagen en la lista de las imágenes.

Para obtener el icono correspondiente a los archivos, se usa una API de la Shell Shell32.dll, luego se hace uso de la función SHGetFileInfo, esta función devuelve información de un archivo, un directorio, etc. En este caso vamos a obtener el icono del archivo, podemos obtener uno de tamaño 16×16, o 32×32.

Adicionamos al proyecto un control ImageList.

Luego el espacio de Nombre:

using System.Runtime.InteropServices;

Después de Class Discos : Form

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

class Win32
{
 public const uint SHGFI_ICON = 0x100;
 public const uint SHGFI_LARGEICON = 0x0; // 'Large icon
 public const uint SHGFI_SMALLICON = 0x1; // 'Small icon


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

private int nIndex = 0;

Creamos una función llamada AsignarIcono, que va a recibir como parámetro la ruta del archivo, que será utilizada para obtener el icono:

private void AsignarIcono(String archivo)
{
 IntPtr hImgSmall;
 IntPtr hImgLarge;
 SHFILEINFO shinfo = new SHFILEINFO();
 //Para obtener el icono 16x16
 hImgSmall = Win32.SHGetFileInfo(archivo, 0, ref shinfo, (uint)Marshal.SizeOf(shinfo), Win32.SHGFI_ICON | Win32.SHGFI_SMALLICON);
 //Para obtener el icono 32x32
 //hImgLarge = SHGetFileInfo(fName, 0,
 //   ref shinfo, (uint)Marshal.SizeOf(shinfo),
 //   Win32.SHGFI_ICON | Win32.SHGFI_LARGEICON);
 System.Drawing.Icon myIcon = System.Drawing.Icon.FromHandle(shinfo.hIcon);
 imageList1.Images.Add(myIcon);
}

Esta función obtiene el icono del archivo, y lo asigna a la lista de imágenes, hay una parte comentada que sirve para obtener el icono de tamaño 32×32 para el que la quiera usar.

En el evento lstDiscos_SelectedIndexChanged, donde cambiábamos el color del nodo si era un archivo, adicionamos lo siguiente:

foreach (FileInfo fi in dir.GetFiles())
{
 TreeNode nodo = new TreeNode();
 nodo.Text = fi.Name;
 nodo.ForeColor = Color.Red;
 AsignarIcono(Path.Combine(fi.DirectoryName, fi.Name));
 nodo.ImageIndex = nIndex;
 nIndex++;
 trvCarpetas.Nodes.Add(nodo);
}

También modificamos el evento trvCarpetas_AfterSelect para que cada vez que busquemos archivos dentro de un directorio, se obtengan los Iconos correspondientes.

Cada vez que se encuentre un nodo que sea un archivo, se va a obtener el icono del archivo, este icono será adicionado al ImageList, la variable nIndex tendrá el índice de la imagen para ser adicionado al Nodo.

Si ejecutamos:

 

Pero hay un problema, que cada vez que se agreguen más archivos al árbol, se van a adicionar más imágenes al ImageList, y habrán imágenes repetidas.

Para corregirlo vamos a guardar en el ImageList un icono por extensión,  se creará un objeto IDictionary que tenga un tipo Int32 que va a representar el índice de la imagen y un tipo String que representa la extensión, cuando encontremos un archivo, buscamos en el objeto IDictionary el índice que equivale a la extensión, luego ese índice será el mismo de la lista de Imágenes, es muy fácil, pero si no entendieron, con el código se entenderá mejor.

Creamos un objeto IDictionary, esta clase es genérica y tiene un valor y una clave para búsqueda, podemos decidir el tipo del valor y de la clave, escribimos lo siguiente justo debajo de prívate int nIndex:

Dictionary<Int32, String> iconos = new Dictionary<Int32, String>(); // indice, extensión

Ahora creamos una función que va a recibir como parámetro la extensión del archivo y va a recorrer el diccionario y se retorna el indice de la extensión, si no se encuentra se devuelve -1:

private Int32 BuscarExtension(String extension)
{
  Int32 indice = -1;
  foreach (KeyValuePair<Int32,String> ico in iconos)
   {
    if (extension == ico.Value)
      {
       indice = ico.Key;
       break;
      }
    }
 return indice;
}

Ahora modificamos el método AsignarIcono, le adicionamos otro parámetro que va a ser la extensión del archivo, y antes de adicionar la imagen a la lista de imágenes, va a buscar si ya antes se había adicionado la imagen:

private void AsignarIcono(String archivo, String extension)
{
 IntPtr hImgSmall;
 IntPtr hImgLarge;
 SHFILEINFO shinfo = new SHFILEINFO();
 //Para obtener el icono 16x16
 hImgSmall = Win32.SHGetFileInfo(archivo, 0, ref shinfo, (uint)Marshal.SizeOf(shinfo), Win32.SHGFI_ICON | Win32.SHGFI_SMALLICON);
 //Para obtener el icono 32x32
 //hImgLarge = SHGetFileInfo(fName, 0,
 //   ref shinfo, (uint)Marshal.SizeOf(shinfo),
 //   Win32.SHGFI_ICON | Win32.SHGFI_LARGEICON);
 System.Drawing.Icon myIcon = System.Drawing.Icon.FromHandle(shinfo.hIcon);
 if (BuscarExtension(extension) == -1) // si no existe
   {
    imageList1.Images.Add(myIcon);
    iconos.Add(imageList1.Images.Count-1, extension);
   }
}

El índice de la imagen va a ser el total de imágenes que tiene el ImageList.

Ahora modificamos la asignación del índice de las imágenes al nodo, en los eventos trvCarpetas_AfterSelect y lstDiscos_SelectedIndexChanged:

foreach (FileInfo fi in file.GetFiles())
{
  TreeNode nodo = new TreeNode();
  nodo.Text = fi.Name;
  nodo.ForeColor = Color.Red;
  AsignarIcono(Path.Combine(fi.DirectoryName, fi.Name), fi.Extension);
  nodo.ImageIndex = BuscarExtension(fi.Extension);
  nIndex++;
  trvCarpetas.SelectedNode.Nodes.Add(nodo);
}

Si ejecutamos sigue igual pero ahorramos mucho espacio en memoria:

 

Código Aquí.

Referencias:

http://support.microsoft.com/kb/319340/es

http://msdn.microsoft.com/en-us/library/bb762179(VS.85).aspx

Deseas comentar o sugerir algo?

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s