2016-06-13 3 views
2

파일 브라우저처럼 작동하는 응용 프로그램을 개발합니다.
디렉터리 내의 파일과 하위 폴더를 나타내는 listview이 있습니다.C# 목록보기에 파일 및 폴더 아이콘 표시

파일 및 폴더를 표시하는 방법 아이콘을 listview에 표시 하시겠습니까?

다음과 같은 방법으로 파일 경로를 목록보기에 추가합니다. 아이콘을 표시하고 싶습니다.

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

* 매우 * 광범위한 질문. LIstView에서 항목의 아이콘을 설정하는 방법을 알려주시겠습니까? 시스템 이미지 목록을 검색하는 방법을 알려주시겠습니까? 또는 각 개별 파일의 아이콘을 검색 하시겠습니까? 크거나 작은 어떤 크기의 아이콘을 원하십니까? –

+0

@CodyGray, 각 아이콘 및 폴더를 적절한 아이콘, 작은 아이콘으로 나타내려고합니다. 감사. – user3165438

답변

4

여러 가지 방법이 있습니다. 한 가지 방법은 ImageList를 만들고 ListView에 링크 한 다음 각 개별 파일의 아이콘을 가져 와서 ImageList에 추가하고 ImageList의 적절한 인덱스에 아이콘을 표시하도록 ListViewItem을 설정하는 것입니다.

또 다른 방법은 쉘이 유지 관리하는 시스템 이미지 목록을 활용하는 것입니다. 이렇게하면 아이콘의 중복 사본을 직접 관리하지 않아도됩니다. ListView에 여러 개의 폴더가 있다고 상상해보십시오. 그들 모두는 동일한 아이콘을 갖지만, 특별한주의를 기울이지 않고도 폴더 아이콘을 사용하는 항목을 표시 할 때 그 폴더 아이콘의 사본을 여러 개 저장할 수 있습니다. 쉘 구현은이 모든 중복 추적을 처리합니다. 시스템 이미지 목록에는 필요한 아이콘 (명시 적으로 요청한 아이콘) 만 포함 된 다음 각각의 단일 복사본 만 포함됩니다. 저는 이것이 더 깔끔하고 우아한 디자인이라고 생각합니다. 그래서 그것을 구현합시다. 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); 
} 

이제 사용해 보도록하겠습니다. 데모 목적을 위해, 나는 listView1 이름, 폼에 ListView 컨트롤을 추가 그것에서 "세부 사항"모드를 표시하도록 설정하고 폼의 Load 이벤트 처리기에 다음 코드를 덤프 :

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 온건주의 검사를 던졌다.

또한 완벽을 기하기 위해 Explorer에서 사용하는 것처럼 ListView 모양을 만들기 위해 코드를 던졌습니다. 그 주소는 SetWindowTheme function입니다.

쉘이하는 것을 다른 일이 있습니다하지만 당신은 여기에 누락 될 것이다. 예를 들어 셸 오버레이 - 소스 제어 시스템에 체크인 된 아이콘과 같은 특정 아이콘에 표시되는 작은 뱃지입니다. 그것은 독자를위한 운동으로 남겨 두었습니다. (힌트 : LVSIL_STATE 플래그는 ListView 컨트롤의 "상태"이미지 목록을 설정하는 데 사용됩니다.) 그들은 당일 Explorer를 작성하지 않았습니다.

+0

시간과 노력에 감사드립니다. 나는 아직 시도하기 전에 당신의 대답을 받아 들였습니다. 한 가지 더 : 처음에 언급 한 짧은 방법을 보여 주시겠습니까? imageList를 사용 하시겠습니까? 고마워요! – user3165438

+0

@user 이렇게 짧지는 않습니다 ... 대부분의 코드는 실제로 동일합니다. 당신이 * 정말로 * 원한다면 그것을 내 대답에 추가 할 수 있지만, 기본적으로 ImageList 객체를 만들어서 ListView에 정상적인 방법으로 할당합니다.그런 다음 foreach 루프 내부에서'SHGFI_ICON' 및'SHGFI_SMALLICON' 플래그를 사용하여'NativeMethods.SHGetFileInfo' 함수를 호출합니다. 그것은'shfi.hIcon' 멤버를 채울 것입니다. 이 아이콘을 사용하여 아이콘 ('Icon.FromHandle (shfi.hIcon)')을 생성하고, 결과 아이콘 객체를 ImageList 객체에 추가하고, 마지막으로 P/호출로'DestroyIcon'을 호출하여'shfi.hIcon'을 삭제합니다 (누출을 방지하기 위해) . –

+0

기본적으로 차이점은 시스템 이미지 목록을 한 번 가져 오는 것입니다. 그런 다음 'SHGetFileInfo'를 호출하면 해당 이미지 목록에있는 아이콘의 색인이 반환됩니다. 다른 방법으로 이미지 목록을 직접 관리하고 SHGetFileInfo를 호출하여 실제 아이콘에 대한 핸들을 얻습니다.이 아이콘은 자체 관리 이미지 목록에 추가해야합니다. –

관련 문제