본문 바로가기

.NET/WinForm

[WinForm] Drag & Drop으로 컨트롤과 컨트롤 간에 개체 옮기기

WinForm에서 Drag & Drop으로 파일 끌어다 놓기에 대한 포스팅을 한 적이 있다.

[.NET Framework/WinForm] - [WinForm] Drag & Drop으로 파일 가져오기

 

[WinForm] Drag & Drop으로 파일 가져오기

파일을 마우스로 끌어서 WinForm의 RichTextBox 컨트롤에 가져다 놓으면 파일을 읽어서 내용을 RichTextBox에 출력해주는 프로그램을 만들어본다. 기본적으로 WinForm의 컨트롤은 Drag&Drop에 대한 처리가 구

cs-solution.tistory.com

 

이번에는 파일 뿐만 아니라 원하는 형식을 지정해서 값을 옮겨다 놓는 방법에 대해 소개하려고 한다.

 

먼저 WinForm에서 컨트롤과 컨트롤 간의 Drag & Drop은 ItemDrag, DragEnter, DragDrop의 3가지의 이벤트 단계를 거쳐 처리된다.

1. ItemDrag

Drag가 시작되었을 때 발생하는 이벤트로 극히 일부의 컨트롤에 존재하는 이벤트이다. 대표적으로 ListView 등이 있으며, 가장 기본적인 ItemContainer의 역할을 수행하는 ListBox조차 이 이벤트가 없다.

이 단계에서 DoDragDrop()으로 끌어서 놓기 작업에 옮겨질 개체를 담는다.

 

2. DragEnter

Drag 한 상태에서 목표 컨트롤에 마우스 커서가 올라왔을 때 발생하는 이벤트로 대부분의 값을 담을 수 있는 컨트롤에 존재하는 이벤트이다.

이 단계에서 DragEventArgs에 담긴 Data 개체의 GetDataPresent()로 담겨있는 데이터의 타입을 검사한다.

검사했을 때 받아들일 수 있는 개체인지 아닌지의 여부를 마우스 커서의 효과를 바꿈으로 사용자에게 알린다.

 

3. DragDrop

DragEnter 상태에서 마우스 버튼을 놓아 개체를 Drop했을 때 발생하는 이벤트로 이 또한 대부분의 컨트롤에 존재하는 이벤트이다.

이 단계에서 Data 개체의 GetData()로 담겨진 데이터를 가져와 처리를 진행한다.

 

 

WinForm에 ListView 2개를 만들고 한쪽에서 다른 한쪽으로 ListViewItem을 Drag & Drop으로 옮기는 코드를 작성해봤다.

public partial class Form1 : Form
{
    // 중략
    
    private void listView_ItemDrag( object sender, ItemDragEventArgs e )
    {
        var listView = sender as ListView;
        
        // 리스트뷰에 선택된 아이템을 배열에 담는다.
        var list = new List<ListViewItem>();
        foreach ( ListViewItem item in listView.SelectedItems ) list.Add( item.Clone() as ListViewItem );
        
        // 만약 끌어서 옮기는 과정이 Copy인지 Move인지에 따라 출발지 ListView에서는 선택해놨던 아이템을 삭제 해줘도 된다. 여기서는 하지 않음.
        
        // 드래그 드롭 시작
        // 위에서 담은 데이터 배열을 data에, 마우스 이펙트는 Copy로 설정
        DoDragDrop( list.ToArray(), DragDropEffects.Copy );
    }
    
    private void listView_DragEnter( object sender, DragEventArgs e )
    {
        if ( e.Data.GetDataPresent( typeof( ListViewItem[] ) ) )
        {
            e.Effect = e.AllowedEffect;    // DoDragDrop에서 설정했던 마우스 이펙트
        }
        else
        {
            e.Effect = DragDropEffects.None;
        }
    }
    
    private void listView_DragDrop( object sender, DragEventArgs e )
    {
        // 이 이벤트는 DragDropEffect가 None인 경우 발생하지 않는다.
        // 여기서 타입 검사를 굳이 다시 할 필요는 없지만 DragDrop이 여러 곳에서 여러 타입으로 이뤄질 수 있다면 하는 것이 좋긴 하다.
        
        var data = ( ListViewItem[] )e.Data.GetData( typeof(ListViewItem[] ) );
        ( sender as ListView ).Items.AddRange( data );
    }
}

 

DragDrop 이벤트를 사용하기 위해서는 아이템이 Drop될 컨트롤의 AllowDrop 속성이 true여야 함을 잊지 말자.