본문 바로가기
Study/C#

C# Windows Forms 강의 43편: Drag & Drop 기능 구현

by wawManager 2025. 3. 18.

1. 강의 개요

이번 강의에서는 Drag & Drop(드래그 앤 드롭) 기능을 사용하여 Windows Forms 애플리케이션에서 데이터를 드래그하여 다른 컨트롤로 옮기는 방법을 학습합니다.
이 기능은 직관적인 UI와 데이터 이동을 구현하는 데 유용합니다.


2. 학습 목표

  1. Windows Forms에서 Drag & Drop의 기본 개념 이해.
  2. 텍스트, 이미지, 객체 등 다양한 데이터를 드래그하고 드롭하는 방법.
  3. 드래그 소스 및 드롭 대상 컨트롤 설정.

3. Drag & Drop 기본 개념

Drag & Drop은 **Drag Source(드래그 소스)**와 Drop Target(드롭 대상) 두 가지 요소로 구성됩니다.

Drag & Drop 동작 단계

  1. 드래그 시작: 사용자가 드래그를 시작하면 DoDragDrop 메서드 호출.
  2. 드롭 가능 여부 확인: 드롭 대상에서 DragEnter 이벤트가 발생하여 데이터가 드롭 가능한지 확인.
  3. 드롭 완료: 사용자가 드롭하면 DragDrop 이벤트가 발생하고 데이터가 처리됨.

Drag & Drop 주요 이벤트

이벤트 설명 예제

MouseDown 드래그 시작 시 호출. DoDragDrop 메서드 호출 listBox1.MouseDown += ListBox1_MouseDown;
DragEnter 드롭 대상에 데이터가 들어왔을 때 호출. listBox2.DragEnter += ListBox2_DragEnter;
DragDrop 데이터가 드롭되었을 때 호출. listBox2.DragDrop += ListBox2_DragDrop;

4. 실습: Drag & Drop으로 데이터 이동

요구사항

  1. ListBox1에서 항목을 드래그하여 ListBox2에 드롭.
  2. 드래그가 가능한 항목만 드롭 가능.
  3. 드롭된 항목은 ListBox1에서 제거되고 ListBox2에 추가.

폼 구성

컨트롤 타입 이름 텍스트 위치 크기

ListBox listBox1 초기 데이터 포함 왼쪽 (150 x 200)
ListBox listBox2 빈 상태 오른쪽 (150 x 200)
Label lblStatus "드래그 상태: 없음" 하단 중앙 (300 x 30)

코드 작성

Form1.cs

using System;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            InitializeDragAndDrop();
        }

        private void InitializeDragAndDrop()
        {
            // ListBox1 초기 데이터 추가
            listBox1.Items.AddRange(new object[] { "사과", "바나나", "체리", "포도", "망고" });

            // ListBox1: 드래그 시작 설정
            listBox1.MouseDown += ListBox1_MouseDown;

            // ListBox2: 드롭 대상 설정
            listBox2.AllowDrop = true;
            listBox2.DragEnter += ListBox2_DragEnter;
            listBox2.DragDrop += ListBox2_DragDrop;
        }

        // ListBox1: MouseDown 이벤트 - 드래그 시작
        private void ListBox1_MouseDown(object sender, MouseEventArgs e)
        {
            if (listBox1.SelectedItem != null)
            {
                lblStatus.Text = "드래그 상태: 시작";
                DoDragDrop(listBox1.SelectedItem, DragDropEffects.Move);
            }
        }

        // ListBox2: DragEnter 이벤트 - 드롭 가능 여부 확인
        private void ListBox2_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(typeof(string))) // 드래그 데이터가 문자열인지 확인
            {
                e.Effect = DragDropEffects.Move; // 드롭 가능
                lblStatus.Text = "드래그 상태: 가능";
            }
            else
            {
                e.Effect = DragDropEffects.None; // 드롭 불가
                lblStatus.Text = "드래그 상태: 불가";
            }
        }

        // ListBox2: DragDrop 이벤트 - 데이터 처리
        private void ListBox2_DragDrop(object sender, DragEventArgs e)
        {
            string droppedItem = (string)e.Data.GetData(typeof(string));
            listBox2.Items.Add(droppedItem); // ListBox2에 항목 추가
            listBox1.Items.Remove(droppedItem); // ListBox1에서 항목 제거
            lblStatus.Text = "드래그 상태: 완료";
        }
    }
}

Form1.Designer.cs

namespace WindowsFormsApp1
{
    partial class Form1
    {
        private System.ComponentModel.IContainer components = null;
        private ListBox listBox1;
        private ListBox listBox2;
        private Label lblStatus;

        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        private void InitializeComponent()
        {
            this.listBox1 = new ListBox();
            this.listBox2 = new ListBox();
            this.lblStatus = new Label();
            this.SuspendLayout();

            // listBox1
            this.listBox1.Location = new System.Drawing.Point(20, 20);
            this.listBox1.Name = "listBox1";
            this.listBox1.Size = new System.Drawing.Size(150, 200);
            this.listBox1.TabIndex = 0;

            // listBox2
            this.listBox2.Location = new System.Drawing.Point(200, 20);
            this.listBox2.Name = "listBox2";
            this.listBox2.Size = new System.Drawing.Size(150, 200);
            this.listBox2.TabIndex = 1;

            // lblStatus
            this.lblStatus.Location = new System.Drawing.Point(20, 240);
            this.lblStatus.Name = "lblStatus";
            this.lblStatus.Size = new System.Drawing.Size(330, 30);
            this.lblStatus.TabIndex = 2;
            this.lblStatus.Text = "드래그 상태: 없음";

            // Form1
            this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 20F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(380, 300);
            this.Controls.Add(this.lblStatus);
            this.Controls.Add(this.listBox2);
            this.Controls.Add(this.listBox1);
            this.Name = "Form1";
            this.Text = "Drag & Drop 예제";
            this.ResumeLayout(false);
        }
    }
}

5. 실행 결과

  1. 초기 상태
    • ListBox1에 "사과", "바나나", "체리" 등의 데이터가 표시됩니다.
    • ListBox2는 비어 있습니다.
  2. 드래그 동작
    • ListBox1의 항목을 클릭한 상태로 드래그 → ListBox2 위로 가져가면 드롭 가능 상태로 표시됩니다.
  3. 드롭 동작
    • 항목을 드롭하면 ListBox1에서 항목이 제거되고, ListBox2에 항목이 추가됩니다.
    • 라벨에 드래그 상태("드래그 상태: 완료")가 업데이트됩니다.

6. 주요 개념 요약

  1. DoDragDrop 메서드
    • 드래그 동작을 시작하고 데이터를 드래그 가능한 상태로 만듦.
  2. DragEnter와 DragDrop 이벤트
    • 드롭 가능 여부 확인 및 데이터 처리 로직 구현.
  3. AllowDrop 속성
    • 드롭 대상 컨트롤에서 반드시 설정해야 드롭 동작을 처리할 수 있음.