ASP.NET AJAX를 사용한 끌어서 놓기 기능의 구현
Jeff Prosise

코드 다운로드 위치: WickedCode2008_01.exe (296 KB)
Browse the Code Online
AJAX를 통해 웹 사용자 인터페이스는 혁신적으로 발전했으며 Visual Studio?? 사용자는 ASP.NET AJAX를 통해 AJAX를 사용할 수 있게 되었습니다. AJAX는 완벽한 테스트 과정을 거친 핵심 AJAX 기능 집합을 제공하는 ASP.NET AJAX Extensions(asp.net/ajax/downloads), 제품 그룹에 의견을 제공할 수 있는 실험적인 기능이 포함된 ASP.NET AJAX Futures(asp.net/downloads/futures) 및 유용한 AJAX 컨트롤과 사용자가 직접 컨트롤을 작성하는 데 사용할 수 있는 SDK를 제공하는 ASP.NET AJAX Control Toolkit(asp.net/ajax/ajaxcontroltoolkit/samples)의 세 가지 다운로드 항목으로 제공됩니다.
이 세 항목 중 Futures 릴리스는 개발자 커뮤니티에서 그다지 주목을 받지 못했습니다. 그러나 Futures CTP(Community Technology Preview)에서는 ASP.NET AJAX의 향후 버전에 대해 대략적으로 살펴볼 수 있을 뿐 아니라 현재 사용되고 있는 최신 웹 응용 프로그램을 작성하는 데 사용할 수 있는 모든 기능이 제공됩니다. 이 기사에서는 이러한 기능 중에서 끌어서 놓기 기능에 대해 알아봅니다.
Futures 다운로드 항목 내에 포함된 PreviewDragDrop.js 파일은 다양한 기능이 제공되는 브라우저 기반 끌어서 놓기 사용자 인터페이스를 지원합니다. 이 파일의 패턴은 기존의 OLE 끌어서 놓기 모델, 즉 끌기 원본이 IDragSource 인터페이스를 구현하고, 놓기 대상이 IDropTarget 인터페이스를 구현하며, 시스템에서 끌기 원본을 놓기 대상에 연결하기 위한 끌어서 놓기 관리자를 제공하는 모델을 기반으로 합니다. Futures의 끌어서 놓기 관리자는 Sys.Preview.UI._DragDropManager라는 JavaScript 클래스 인스턴스로 자동으로 인스턴스화되며 Sys.Preview.UI.DragDropManager 전역 변수를 통해 사용할 수 있습니다.
필자는 최근 몇 달 동안 PreviewDragDrop.js를 사용하여 사용자 지정 끌기 원본 및 사용자 지정 놓기 대상이 제공되는 실제 끌어서 놓기 기능을 구현하는 방법을 보여 주는 샘플을 작성해 왔습니다. 그리고 결국 쓸 만한 샘플을 완성했습니다. 이 샘플을 작성하는 과정에서 사용자 지정 끌기 시각 효과를 추가하여 DragDropManager를 개선하는 방법을 포함해 DragDropManager에 대해 많은 것을 배울 수 있었습니다. 이 모델 및 JavaScript에서 클래스를 파생하고 인터페이스를 구현하는 작업의 개념을 익히고 나면 DragDropManager를 통해 웹 UI에 더욱 다양한 기능을 추가할 수 있게 될 것입니다.

끌어서 놓기 실행
실제 코드를 실행하기 전에 먼저 이 기사에 포함된 샘플 프로젝트를 다운로드하여 간략하게 살펴보도록 하겠습니다. Visual Studio의 웹 사이트 열기 명령을 사용하여 프로젝트를 연 다음 브라우저에 홈 페이지(DragDropDemo.aspx)를 표시합니다. 이 샘플을 실행하려면 ASP.NET AJAX Extensions가 설치되어 있어야 합니다. Futures CTP는 사이트의 Bin 폴더에 이미 포함되어 있기 때문에 따로 다운로드하여 설치하지 않아도 됩니다.
페이지의 위쪽에는 5가지 색 견본이 표시되고 아래쪽에는 "Drop It Here(여기에 놓으십시오)"라는 레이블이 있는 빈 상자가 표시됩니다(그림 1 참조). 여기서 색 견본이 끌기 원본이고 빈 상자가 놓기 대상입니다. 색 견본 중 하나를 마우스로 클릭하여 아래의 빈 상자로 끕니다. 마우스 커서가 상자 안으로 들어가면 상자의 색이 흰색에서 밝은 회색으로 바뀝니다. 이 기능을 놓기 대상 강조 표시라고 합니다. 끌어온 색 견본을 상자에 놓으면 상자의 색이 끌어서 놓은 견본의 색으로 바뀝니다.
그림 1DragDropDemo.aspx 실행 화면(더 크게 보려면 이미지를 클릭하십시오.)
다른 색 견본을 끌어 화면에서 이리저리 움직여 보십시오. 그러면 견본을 놓기 대상에만 놓을 수 있으며, 견본을 놓을 수 있는 위치에서는 커서의 모양이 바뀜을 알 수 있습니다. 또한 색 견본을 끌 때 부분적으로 투명한 견본 표현("끌기 시각 효과")이 커서를 따라 표시되므로 끌고 있는 항목을 확인할 수 있습니다. 이 기사의 뒷부분에서도 설명하겠지만 사용자는 이 끌기 시각 효과를 만들기 위한 코드만 작성하면 됩니다. 커서와 함께 끌기 시각 효과를 이동하고 각각의 마우스 이동에 대해 커서를 업데이트하는 등의 다른 모든 작업은 ASP.NET AJAX에서 처리됩니다.
이 페이지가 작동하도록 하는 사용자 지정 논리는 웹 사이트 Scripts 폴더의 ColorDragDrop.js 스크립트 파일에 있습니다. ColorDragDrop.js는 ScriptManager에서 로드하는 사용자 지정 스크립트 파일입니다. 실제로 소스 뷰에서 DragDropDemo.aspx를 열면 ScriptManager가 세 개의 스크립트 파일, 즉 이 데모에서 사용되는 주요 ASP.NET AJAX 기본 클래스를 포함하는 PreviewScript.js, ColorDragDrop.Js에서 사용하는 끌어서 놓기 지원이 포함된 PreviewDragDrop.js 및 ColorDragDrop.js 자체를 로드함을 확인할 수 있습니다.

DragDropManager
ASP.NET AJAX를 사용하여 다양한 기능이 제공되는 끌어서 놓기 사용자 인터페이스를 작성하기 위해서는 먼저 Sys.Preview.UI._DragDropManager 클래스(이하 DragDropManager)에 대해 알아보아야 합니다. 내부적으로 DragDropManager는 호스트 브라우저 유형에 따라 대부분의 작업을 Sys.Preview.UI.IEDragDropManager 또는 Sys.Preview.UI.GenericDragDropManager 인스턴스에 위임합니다. DragDropManager의 공용 인터페이스는 10여 개의 메서드로 구성되는데, 그 중 끌어서 놓기 기능 구현에 중요한 역할을 하는 것은 다음의 세 메서드입니다.
  • startDragDrop—끌어서 놓기 작업을 시작합니다.
  • registerDropTarget—개체를 놓기 대상으로 등록합니다.
  • unregisterDropTarget—놓기 대상의 등록을 취소합니다.
startDragDrop 메서드를 호출하고 나면 기본적으로 DragDropManager는 진행 중인 마우스 이벤트를 모니터링하고, 커서 아래에 있는 끌기 원본과 놓기 대상(있는 경우)에 대해 관련 알림을 전달하고, 현재 위치에서 놓기를 수행하는 경우 발생하는 현상을 시각적으로 표시하기 위해 커서의 모양을 지정하는 작업을 수행합니다. DragDropManager는 이러한 작업을 수행하기 위해 mousemove 및 mouseup 등의 주요 이벤트에 대해 자체 처리기를 등록하며, 이들 이벤트 처리기에서 끌고 있는 원본에 대해 IDragSource 메서드를 호출하고 커서 아래의 놓기 대상에 대해 IDropTarget 메서드를 호출합니다.
예를 들어 페이로드를 끄는 커서가 놓기 대상의 경계 내로 이동하면 DragDropManager는 끌기 원본의 get_dragDataType, get_dragMode 및 getDragData 메서드를 호출하여 페이로드에 대한 정보를 가져옵니다. 그런 다음 결과를 놓기 대상의 canDrop 메서드로 전달하여 끌기 원본과 놓기 대상이 호환되는지 여부를 결정합니다. 끌어 온 원본을 놓으면 DragDropManager는 drop 메서드를 호출하여 끌기 원본에서 가져온 데이터를 다시 전달함으로써 놓기 대상에 놓기 작업을 알립니다.
DragDropManager는 놓기 대상으로 등록된 개체에 대한 내부 참조 배열을 유지 관리하므로 커서가 놓기 대상 위에 있는지 여부를 확인할 수 있습니다. 개체는 DragDropManager의 registerDropTarget 메서드를 호출하여 배열에 추가되며, unregisterDropTarget 메서드를 호출하여 배열에서 제거됩니다. DragDropManager에서 놓기 대상을 대신해 등록하는 연결된 이벤트 처리기의 등록을 취소할 수 있도록 하려면 사용자가 등록한 해당 놓기 대상의 등록을 취소해야 합니다. 이렇게 하지 않으면 메모리 누수가 발생할 수 있습니다.
DragDropManager는 끌기 원본과 놓기 대상을 연결하는 역할을 합니다. 그러므로 DragDropManager가 없다면 끌어서 놓기 사용자 인터페이스가 작동하도록 하기 위해 엄청난 양의 코드를 작성해야 할 것입니다. 특히 이 사용자 인터페이스를 여러 가지 종류의 브라우저에서 사용해야 하는 경우에는 작성해야 하는 코드의 양도 크게 늘어납니다.

끌기 원본 작성
끌기를 수행하려면 끌 항목, 즉 끌기 원본이 있어야 합니다. ASP.NET AJAX에서 끌기 원본은 PreviewDragDrop.js에서 정의되는 IDragSource 인터페이스를 구현하는 개체입니다. 그림 2에는 이 인터페이스에 속하는 메서드의 목록이 나와 있습니다.
JavaScript가 명시적으로 인터페이스를 지원하지 않는데 JavaScript에서 인터페이스를 구현한다는 것이 이상하게 생각될 수도 있습니다. 또한 JavaScript에서는 클래스, 상속, 네임스페이스 및 기타 OOP(개체 지향 프로그래밍) 기능도 명시적으로 지원되지 않습니다. 그러나 ASP.NET AJAX의 클라이언트 부분인 Microsoft?? AJAX Library는 전적으로 JavaScript로 구현된 클래스 라이브러리입니다. 이 라이브러리는 널리 알려져 있는 JavaScript 프로그래밍 기술을 사용하여 OOP를 가장합니다. 이러한 기술을 사용하면 클래스를 직접 만들 수 있으며, 만든 클래스에서 인터페이스를 구현하고 특정 클래스에서 다른 클래스를 파생할 수도 있습니다.
ColorDragDrop.js에는 JavaScript 클래스 쌍인 ColorDragSourceBehavior 및 ColorDropTargetBehavior가 포함되어 있습니다. 이 중 ColorDragSourceBehavior는 IDragSource를 구현하며, 두 클래스 모두 Custom.UI 네임스페이스에 속합니다.
Microsoft AJAX Library 스타일로 JavaScript 클래스를 만들려면 먼저 이름이 클래스 이름과 같은 함수를 정의합니다. 이 함수는 클래스 생성자 역할을 합니다.
Custom.UI.ColorDragSourceBehavior = function(element, color){    Custom.UI.ColorDragSourceBehavior.initializeBase(this, [element]);    this._mouseDownHandler = Function.createDelegate(this,        this.mouseDownHandler);    this._color = color;    this._visual = null;}
그런 다음 JavaScript 프로토타입 속성을 사용하여 모든 클래스 인스턴스에 포함할 메서드를 정의합니다.
Custom.UI.ColorDragSourceBehavior.prototype ={    // 메서드 위치}(참고: 프로그래머 주석은 예제 프로그램 파일에는 영문으로 제공되며 기사에는 이해를 돕기 위해 번역문으로 제공됩니다.)
JavaScript는 강력한 형식 지정 또는 형식 리플렉션을 지원하지 않으므로 Microsoft AJAX Library에서 이 작업을 수행합니다. registerClass 및 registerNamespace와 같은 Type 클래스의 메서드(ASP.NET AJAX 코어의 일부인 MicrosoftAjax.js에 있음)를 사용하면 작성한 클래스를 등록하여 네임스페이스에 할당할 수 있습니다. 그러면 나중에 Microsoft AJAX Library에서 JavaScript의 기본 제공 Object 형식에 추가하는 getTypeName 등의 메서드를 사용하여 등록한 형식을 리플렉션할 수 있습니다.
Type 클래스에서 제공하는 또 다른 필수 인프라 요소는 파생 클래스의 해당하는 메서드에서 기본 클래스 메서드를 호출하는 메커니즘입니다. 즉, 클래스 생성자에서 initializeBase를 호출하여 기본 클래스의 생성자를 호출하고, 파생 클래스의 메서드 재정의에서 callBaseMethod를 호출하여 기본 클래스의 해당 메서드를 호출합니다.
그림 3에 나와 있는 ColorDragSourceBehavior 클래스는 이러한 도구를 모두 사용하여 일반 DOM 요소를 사용이 간편한 단일 클래스의 끌기 원본으로 변환하는 데 필요한 논리를 캡슐화합니다. registerClass를 호출하면 ColorDragSourceBehavior가 IDragSource 인터페이스뿐 아니라 MicrosoftAjax.js에서 정의되는 Sys.UI.Behavior라는 ASP.NET AJAX 기본 클래스에서도 파생됩니다. IDragSource는 ColorDragSourceBehavior가 끌기 원본으로 작동하도록 하며, Sys.UI.Behavior는 ColorDragSourceBehavior 인스턴스가 DOM 요소에 연결되어 요소의 동작을 수정하도록 합니다.
get_dragDataType, getDragData 등 ColorDragSourceBehavior가 구현하는 대부분의 메서드는 IDragSource 인터페이스의 멤버입니다. 그러나 ColorDragSourceBehavior는 IDragSource에 속하지 않는 일부 메서드도 구현합니다. 예를 들어 initialize 메서드는 mousedown 이벤트에 대해 처리기를 등록하여 끌기 원본이 끌어서 놓기 작업을 시작하기 위해 DragDropManager.startDragDrop을 호출할 수 있도록 합니다. 그리고 dispose 메서드는 메모리 누수를 방지하기 위해 이벤트 처리기의 등록을 취소합니다.
IDragSource 메서드 자체는 매우 단순합니다. get_dragDataType은 "DragDropColor" 문자열을 반환하여 ColorDragSourceBehavior가 놓기 대상에 제공하는 데이터(샘플의 경우에는 색 데이터)의 형식을 확인합니다. getDragData는 끌기 원본이 표시하는 색을 정의하는 문자열을 반환하며, get_dragMode는 현재 시점에 끌기 원본을 놓는 경우 해당 원본은 이동되는 것이 아니라 복사됨을 나타내는 Sys.Preview.UI.DragMode.Copy를 반환합니다. 이때 PreviewDragDrop.js 파일에서 Sys.Preview.UI.DragMode.Copy와 함께 정의되는 Sys.Preview.UI.DragMode.Move를 사용할 수도 있습니다.
ColorDragSourceBehavior가 끌기 시각 효과를 처리하는 방식에 대해서도 잠시 설명하겠습니다. mousedown 이벤트 처리기는 DragDropManager의 startDragDrop을 호출하여 끌어서 놓기 작업을 시작합니다. 그러나 처리기는 startDragDrop을 호출하기 전에 먼저 cloneNode를 호출하여 끌기 원본이 나타내는 DOM 요소를 복제합니다. 그런 다음 처리기는 복제된 노드의 불투명도를 40%로 설정하고, 노드를 브라우저 DOM에 삽입한 다음, 새 노드에 대한 참조를 startDragDrop에 대한 매개 변수로 DragDropManager에 전달합니다. 그러면 DragDropManager는 끌기 시각 효과가 커서를 따라 이동하도록 시각 효과의 움직임에 애니메이션을 적용하는 작업을 수행합니다.

놓기 대상 작성
코드 다운로드에 포함된 ColorDragDrop.js의 ColorDropTargetBehavior 클래스는 DOM 요소를 놓기 대상으로 변환하는 논리를 캡슐화합니다. 이 클래스는 Sys.UI.Behavior에서 파생되므로 DOM 요소에 연결할 수 있으며 IDropTarget 인터페이스를 구현하므로 놓기 대상 역할을 할 수 있습니다. 그림 4에는 IDropTarget의 멤버 목록이 나와 있습니다.
ColorDropTargetBehavior의 onDragEnterTarget 및 onDragLeaveTarget 메서드는 앞서 살펴본 놓기 대상 강조 표시를 수행합니다. 페이로드를 끄는 커서가 놓기 대상으로 들어가면 DragDropManager는 onDragEnterTarget을 호출합니다. 페이로드가 올바른 형식(DragDropColor)인 경우 onDragEnterTarget은 대상의 현재 배경색을 필드에 저장하고 배경색을 밝은 회색으로 변경합니다. 커서가 페이로드를 놓지 않고 계속 끌면서 놓기 대상 영역을 벗어나면 DragDropManager는 놓기 대상의 onDragLeaveTarget 메서드를 호출합니다. 이 메서드의 ColorDropTargetBehavior 구현에서는 놓기 대상의 원래 배경색을 복원합니다.
페이로드를 끄는 커서가 놓기 대상 위를 이동할 때마다 DragDropManager는 놓기 대상의 canDrop 메서드를 호출하여 대상에 원본을 놓을 수 있는지 여부를 확인합니다. ColorDropTargetBehavior.canDrop은 페이로드 형식을 확인하여 형식이 DragDropcolor이면 true를 반환하고 그렇지 않으면 false를 반환합니다. 이 과정에 DragDropManager 클래스는 커서를 통해 사용자에게 필요한 시각적 피드백을 제공할 수 있습니다.
놓기를 수행하면 놓기 대상의 drop 메서드가 호출됩니다. ColorDropTargetBehavior.drop 메서드는 끌기 원본에서 색을 추출하여 그에 따라 자체 배경색을 설정합니다. 실제로 이 색은 놓기 대상 역할을 하는 DOM 요소의 색입니다.
drop 메서드로 전달되는 dragMode 매개 변수는 끌기 모드(이동 또는 복사)를 지정합니다. 궁극적으로 끌기 모드에 맞도록 브라우저의 DOM을 조작하는 것은 놓기 대상입니다. DragDropDemo.aspx에서는 복사 모드만 지원되므로 놓기 대상은 자체 배경색을 끌기 원본에 포함된 색으로 설정함으로써 끌기 원본을 "복사"하게 됩니다. 이동 모드도 지원되는 경우에는 놓기를 성공적으로 완료한 후에 놓기 대상이 끌기 모드를 확인해야 하며 dragMode가 Sys.Preview.UI.DragMode.Move로 설정되어 있으면 끌기 원본과 연결된 DOM 요소를 삭제하거나 재배치해야 합니다.

끌기 원본 및 놓기 대상 만들기
ColorDragSourceBehavior 및 ColorDropTargetBehavior을 구현하고 나면 끌기 원본 및 놓기 대상이 포함된 페이지를 쉽게 작성할 수 있습니다. 그림 5에는 DragDropDemo.aspx의 관련 태그 및 코드가 나와 있습니다.
끌기 원본으로 사용되는 색 견본은 배경색이 빨강, 노랑 및 초록 등으로 설정된 DIV입니다. JavaScript의 pageLoad 함수는 5개의 ColorDragSourceBehavior 개체를 인스턴스화하고 이러한 DIV 중 하나에 할당하여 DIV를 끌기 원본으로 변환합니다. 끌기 원본의 initialize 메서드를 호출하면 각 끌기 원본이 해당 mousedown 이벤트 처리기를 등록할 수 있습니다.
놓기 대상도 역시 DIV입니다. 첫 번째 문이 ColorDropTargetBehavior 개체를 인스턴스화하고 DIV에 연결하여 DIV를 놓기 대상으로 변환합니다. 그리고 두 번째 문이 ColorDropTargetBehavior의 initialize 메서드를 호출하여 DragDropManager에 놓기 대상으로 등록합니다.
ColorDragSourceBehavior 및 ColorDropTargetBehavior는 색을 끌어서 놓을 수 있도록 하기 위해 특수하게 작성된 것입니다. 다른 끌어서 놓기 시나리오를 지원하기 위해 이와 같은 클래스를 작성할 수 있습니다. 예를 들어 사용자가 사진을 폴더 간에 끌어서 구성할 수 있는 사진 공유 사이트를 작성하는 경우를 가정해 보겠습니다. 이 경우 DIV를 사용하여 폴더를 표시하고 PhotoDropTargetBehavior 클래스를 작성해 DIV를 놓기 대상으로 변환할 수 있습니다. 그리고 PhotoDragSourceBehavior 클래스를 작성하여 DOM 이미지 요소를 끌기 가능한 사진으로 변환할 수 있습니다. 이렇게 작성하는 클래스의 사용은 거의 특정 응용 프로그램에만 국한되지만 모두 이 칼럼에 나와 있는 끌기 소스 및 놓기 대상 클래스 예와 동일한 패턴을 따릅니다.

끌어서 놓기 외의 기능 구현
ASP.NET AJAX는 AJAX 기능을 웹 페이지에 추가할 수 있는 편리한 도구이며, ASP.NET AJAX Futures 릴리스에는 핵심 플랫폼에서 유용하게 사용할 수 있는 향상된 기능이 추가되었습니다. 끌어서 놓기 사용자 인터페이스 지원은 이러한 향상된 기능의 한 가지 예일 뿐이며 애니메이션, 클라이언트 쪽 데이터 바인딩 및 기타 편리한 DOM 추상화 기능도 다양하게 제공됩니다. 이러한 기능은 즉시 사용할 수 있으며 향후 핵심 기능으로 추가될 수도 있습니다. 앞으로 ASP.NET AJAX 응용 프로그램에서 이러한 기능을 사용하여 응용 프로그램의 기능을 더욱 향상시켜 보시기 바랍니다.
Futures의 PreviewGlitz.js 파일에 포함되어 있는 클래스를 사용하여 웹 페이지에 애니메이션을 추가하는 방법에 대한 다른 예를 보려면 wintellect.com/cs/blogs/jprosise/archive/2007/04/04/Creating-Sophisticated-Animations-with-the-Microsoft-AJAX-Library.aspx에서 필자가 작성한 "Microsoft AJAX Library를 사용하여 복잡한 애니메이션 만들기"라는 제목의 블로그 게시물을 참조하십시오.

Jeff에게 질문이나 의견이 있으면 다음 전자 메일 주소로 보내시기 바랍니다:wicked@microsoft.com.


Jeff ProsiseMSDN Magazine 편집자이며 Programming Microsoft .NET(Microsoft Press, 2002)을 비롯한 여러 권의 책을 집필했습니다. 또한 Microsoft .NET Framework를 전문적으로 다루는 소프트웨어 컨설팅 및 교육 업체인 Wintellect(www.wintellect.com)의 공동 설립자이기도 합니다. Jeff에게 연락하려면 wicked@microsoft.com으로 전자 메일을 보내시면 됩니다.

Posted by 퓨전마법사
,