개발 과정 따라가기

WinForms로 파일 탐색기 구현하기 (1)

calendar2 2026. 7. 3. 12:57

어쩌다보니 C#을 다루는 직장으로 이직하게 되었다. 요즘 대부분의 웹/앱 개발에서는 개발자가 직접 코드 타이핑을 하는 경우는 거의 없지만 아직 게임 개발이나 SCADA 프로그램 개발쪽은 변화 속도가 많이 느린 것 같다.

조만간 과제를 하나 부여받을 예정인데, 그때 AI를 최대한 사용하지 않고 프로그램을 만드는 과제를 받을 예정이다. 따라서, 오랜만에 직접 타이핑하며 코드를 따라가며 학습하는 정통적인 방식으로 돌아와봤다.

 

또한, C# 뿐만 아니라 개인적으로 다른 언어나 토이 프로젝트로 구현하는 코드에 대해서 가끔씩 이렇게 개발 과정 따라가기 시리즈로 올려볼 예정이다.

1. Visual Studio 설치 및 프로젝트 생성

우선, Visual Studio를 설치한다. C# 언어의 경우 만능 툴인 VS Code와 JetBrains사의 Rider 라는 IDE로 코딩이 가능한데, 앞서 말했듯 이 언어를 다루는 회사 자체가 보수적이고 변화의 둔하다. 그래서 대부분 Visual Studio로 개발하며 Rider의 경우 단순한 프로그램 개발보다는 게임 개발일경우 조금 더 채택되는 분위기다.

 

IDE 설치 과정은 지금 여기에 올리진 않겠다. 검색하면 바로 알 수 있는 정보기도 하고 아직 이 블로그에 설치 과정에 대한 글이 없다. Visual Studio를 설치하고 실행하면 다음과 같은 순서로 프로젝트를 생성한다.

  1. 새 프로젝트 만들기(Create a new project) 클릭
  2. 템플릿 목록에서 Windows Forms App 선택

템플릿을 선택하면 다음 정보들을 설정해주면 된다.

  • Project name: MyFileExplorer
  • Location: 프로젝트를 저장할 디렉토리 경로
  • Framework: 당신이 설치한 Visual Studio에 따라 최신 안정 버전(LTS) 선택 → 참고로, 닷넷 10이 현재까지 가장 최신의 LTS다

프로젝트를 생성하면 다음과 같은 파일들이 생성된 것을 확인할 수 있다.

  • Program.cs → 프로그램의 진입점. Main 메서드가 여기에 있다
  • Form1.cs 첫 번째 화면
  • Form1.Designer.cs 화면에 버튼·목록 같은 걸 배치하면 그 배치 코드가 자동으로 이곳에 쌓인다
  • Form1.cs [Design] 디자인된 Form1 화면을 IDE에서 화면으로 볼 수 있다

2. 레이아웃 나누기

위 파일들을 확인했다면 프로젝트가 정상적으로 생성된 상태이다. 이제 파일 탐색기를 만들기 위해 화면의 레이아웃을 나눠보자.

다음 세 가지 컨트롤을 사용할 예정이다.

  • SplitContainer: 화면을 두 칸으로 나누고, 가운데 경계선을 마우스로 드래그해서 비율을 조절할 수 있게 해주는 컨테이너
  • TreeView: 폴더를 계층적으로(들여쓰기 되면서 펼쳐지는) 보여주는 컨트롤
  • ListView: 항목들을 목록으로 보여주는 컨트롤

Form1.cs [Design]을 열어서 도구 상자(Toolbox)를 보자. 만약, 도구 상자가 안 보인다면 상단 메뉴에서 보기(View) > 도구 상자를 클릭하자. 그리고 다음 순서대로 하나씩 컨트롤을 배치한다.

  1. 먼저 SplitContainer를 창 위로 드래그해서 놓는다. 놓으면 창을 좌우로 꽉 채우면서 가운데 분할선이 생긴다.(만약 위아래로 나뉘어 있으면, 그 컨트롤을 클릭한 뒤 오른쪽 속성(Properties) 창에서 OrientationVertical로 바꾸면 좌우 분할이 된다)
  2. TreeView를 드래그해서 SplitContainer의 왼쪽 칸 안에 놓는다.
  3. ListView를 드래그해서 SplitContainer의 오른쪽 칸 안에 놓는다.

TreeViewListView까지 배치한 후에 각 컨트롤이 SplitContainer의 내부를 꽉 채우지 않는경우 속성 창에서 Dock 속성을 Fill로 설정하면 컨트롤이 칸에 딱 맞게 늘어난다.

또한, 각 컨트롤의 이름도 미리미리 정리하자. 아마 컨트롤을 배치한 후에 아무런 조치도 취하지 않았다면 treeView1, listView1 이럲게 자동으로 이름이 붙었을 것이다. 코드에서 이 이름으로 컨트롤에 접근하게 되니, 속성 창의 맨 위 (Name) 항목에서 알아보기 쉬운 이름으로 바꿔두면 나중에 편해진다.

각각 treeViewFolderslistViewFiles로 변경해두자. 여기까지 완료하고 프로그램을 실행(Ctrl + F5)하면 창이 좌우로 나뉘어 있는 화면을 볼 수 있을 것이다.

 

참고로, 컨트롤을 배치한 지금 Form1.Designer.cs 파일을 보면 우리가 직접 마우스로 클릭해서 배치한 컨트롤에 대해서 코드가 작성되어 있는 것을 확인할 수있다.

3. 왼쪽 TreeView에 실제 드라이브 채우기

레이아웃이 나뉘었으니 이제 실제로 내 PC의 C 드라이브와 D 드라이브를 탐색해서 왼쪽 TreeView에 배치해보자.

이번 step에서는 아래와 같은 클래스들이 도입된다.

  • DriveInfo: 내 PC에 붙어있는 드라이브(C, D, USB 등) 정보를 다루는 클래스
  • TreeNode: TreeView에 들어가는 "한 줄(항목) 하나"를 나타내는 객체

Form1.cs 파일을 열자. 디자이너 화면에서 F7을 누르거나, 오른쪽 솔루션 탐색기에서 Form1.cs을 우클릭 → 코드 보기(View Code) 하면 열 수 있다. 파일을 열면 이런 코드가 보일 것이다.

public Form1()
{
    InitializeComponent();
}

 

Java를 다루신 분들은 익숙할텐데, Form1() 생성자이다. 이제 코드를 추가해서 다음과 같은 코드로 만들어보자.

public Form1()
{
    InitializeComponent();
    LoadDrives();          // ← 추가
}

private void LoadDrives()
{
    foreach (DriveInfo drive in DriveInfo.GetDrives())
    {
        TreeNode node = new TreeNode(drive.Name);      // 화면에 보일 텍스트: "C:\"
        node.Tag = drive.RootDirectory.FullName;       // 숨겨둘 실제 경로: "C:\"
        treeViewFolders.Nodes.Add(node);               // 트리에 이 노드를 추가
    }
}

 

여기까지 완료했다면 다시 프로그램을 실행하여 확인해보자. 아마 왼쪽 TreeView 영역에 당신 PC의 드라이브가 나오는 것을 확인할 수 있다.

4. TreeView에 하위 폴더 채우기

4-1. 드라이브 노드에 가짜 자식 붙이기

이제 C 드라이브를 클릭하면 C 드라이브 안에 하위 폴더들을 볼 수 있도록 만들 예정이다. 여기서 주의할 점이 PC의 폴더는 수십만 개라, 만약 프로그램을 시작하자마자 모든 폴더를 전부 다 읽어서 트리에 넣을 경우 프로그램이 멈춰버린다. 그래서 여기서는 "사용자가 C 드라이브를 클릭하는 순간에 하위 폴더 한 층만" 읽어오는 방식(지연 로딩)을 사용하려 한다.

하지만 이 방식에도 얄궂은 문제가 있다. TreeView는 자식 노드가 하나라도 있어야 펼치기 버튼을 그려준다. 문제는 우리가 지연 로딩 방식을 선택했기 때문에 펼치기 버튼이 안 뜨고, 펼치지 못 하면 지연 로딩을 할 수가 없어진다.

따라서, "가짜 자식(dummy)"를 미리 넣어두는 방식으로 이 문제를 해결하겠다. 아래 코드를 추가해보자.

private void LoadDrives()
{
    foreach (DriveInfo drive in DriveInfo.GetDrives())
    {
        TreeNode node = new TreeNode(drive.Name);
        node.Tag = drive.RootDirectory.FullName;
        node.Nodes.Add("dummy");   // ← 추가: 펼치기 화살표가 생기도록 가짜 자식
        treeViewFolders.Nodes.Add(node);
    }
}

 

노드 하위에 가짜 자식(dummy)를 추가했다. 이 상태로 확인해보면 펼치기 버튼이 생긴 것을 확인할 수 있을 것이다. 물론, 아직은 펼쳐도 하위 폴더가 나오지 않는다. 이제 실제로 펼치기 버튼을 클릭했을 때 하위 폴더를 탐색하여 가져올 수 있도록 설정해보자.

4-2. 이벤트를 트리에 연결하기

다시 디자이너로 돌아가자. 여기서 TreeView쪽에 이벤트를 만들 생각이다.

  1. 디자이너에서 TreeView를 클릭해 선택
  2. 오른쪽 속성(Properties) 창 상단의 번개 모양 아이콘(이벤트 탭)을 클릭
  3. 목록에서 BeforeExpand를 찾아 그 칸을 더블클릭

4-3. BeforeExpand 메서드 로직 작성

이렇게 이벤트를 만들면 Form1.cs 파일에 treeViewFolders_BeforeExpand 라는 메서드가 생성된 것을 확인할 수 있다. 이 메서드에 아래와 같이 로직을 작성해주자.

private void treeViewFolders_BeforeExpand(object sender, TreeViewCancelEventArgs e)
{
    TreeNode node = e.Node;   // 지금 펼치려는 그 노드

    // 아직 가짜 자식만 들어있는 상태라면 → 진짜 폴더를 채운다
    if (node.Nodes.Count == 1 && node.Nodes[0].Text == "dummy")
    {
        node.Nodes.Clear();                 // 가짜 자식 제거
        string path = (string)node.Tag;     // 아까 심어둔 실제 경로 꺼내기 (형변환)

        try
        {
            foreach (string dir in Directory.GetDirectories(path))
            {
                TreeNode child = new TreeNode(Path.GetFileName(dir));
                child.Tag = dir;
                child.Nodes.Add("dummy");   // 이 폴더도 나중에 펼칠 수 있게 또 가짜 자식
                node.Nodes.Add(child);
            }
        }
        catch (UnauthorizedAccessException)
        {
            // 접근 권한 없는 폴더(시스템 폴더 등)는 그냥 건너뜀
        }
    }
}

 

이렇게 BeforeExpand 메서드 로직을 작성하고 테스트해보면 왼쪽 TreeView에서 펼치기 버튼을 통해 하위 폴더를 조회할 수 있음을 확인할 수 있다.

5. 오른쪽 ListView에서 파일 조회하기

이제 이번 목표의 마지막인 왼쪽 TreeView에서 폴더를 클릭하면 오른쪽 ListView에서 폴더에 해당하는 파일을 조회하는 로직을 완성해보자.

5-1. ListView를 표 모양으로 초기화

우리 파일 탐색기를 떠올려보자. 오른쪽 ListView쪽은 파일명, 파일 용량, 수정한 날짜 등등 마치 표 형식처럼 되어있다. 따라서, 다음 코드를 추가하여 ListView를 표 모양으로 만들자.

public Form1()
{
    InitializeComponent();
    SetupFileList();    // ← 추가
    LoadDrives();
}

private void SetupFileList()
{
    listViewFiles.View = View.Details;        // 표(자세히) 모드로 전환
    listViewFiles.Columns.Add("이름", 200);    // 1번째 열, 폭 200
    listViewFiles.Columns.Add("크기", 100);    // 2번째 열
    listViewFiles.Columns.Add("수정한 날짜", 150); // 3번째 열
}

5-2. AfterSelect 이벤트 연결

이번에는 AfterSelect라는 이벤트를 사용한다. 왼쪽 TreeView에서 폴더를 선택하면 오른쪽 ListView에 파일이 뜨는 형식이다.

  1. 디자이너에서 TreeView 클릭
  2. 속성 창의 번개 아이콘(이벤트 탭)
  3. AfterSelect 칸을 더블클릭

5-3. AfterSelect 로직 작성하기

앞서 BeforeExpand 이벤트를 설정한 경험처럼 5-2번을 수행하면 Form1.cs 파일에 treeViewFolders_AfterSelect 라는 메서드가 생성된다. 이 메서드의 로직을 아래와 같이 작성해준다.

private void treeViewFolders_AfterSelect(object sender, TreeViewEventArgs e)
{
    string path = (string)e.Node.Tag;   // 선택된 노드의 실제 경로 꺼내기
    listViewFiles.Items.Clear();          // 이전 폴더의 목록 비우기

    try
    {
        foreach (string file in Directory.GetFiles(path))
        {
            FileInfo info = new FileInfo(file);

            ListViewItem item = new ListViewItem(info.Name);  // 1열: 이름
            item.SubItems.Add(info.Length.ToString());        // 2열: 크기
            item.SubItems.Add(info.LastWriteTime.ToString()); // 3열: 수정 날짜

            listViewFiles.Items.Add(item);
        }
    }
    catch (UnauthorizedAccessException)
    {
        // 권한 없는 폴더는 조용히 건너뜀
    }
}

 

이제 마지막 테스트를 해보자. 프로그램이 좌우로 레이아웃이 분할되어 있고, 왼쪽 TreeView 영역에서는 내 PC의 드라이브가 조회되며 드라이브를 펼치면 하위 폴더가 보일 것이다. 각 폴더를 클릭하면 오른쪽 ListView 영역에 그 폴더의 파일들이 표시되는 것을 확인할 수 있다.