diff --git a/doc/진행상황.md b/doc/진행상황.md
index 43855b6..d3098e4 100644
--- a/doc/진행상황.md
+++ b/doc/진행상황.md
@@ -132,7 +132,7 @@ CommunityToolkit 커맨드는 CommandManager 를 구독하지 않는데 이 둘
| ~~취소~~ | ~~D-4 비교 창 여러 개~~ (2026-09-09 사용자 판단으로 뺌) |
| **완료** | D-5 덩어리 단위 반영 (3-Way 에서 BASE 를 가져오던 것을 REMOTE 로) |
| **완료** | D-6 비교 결과 텍스트 내보내기 |
-| **완료**(화면 확인 남음) | D-7 드래그 앤 드롭으로 열기 |
+| **완료** | D-7 드래그 앤 드롭으로 열기 |
### E. 추가 요청 (2026-09-09 오후)
@@ -203,7 +203,7 @@ BASE 머리글에 그렇게 적었다 - `BASE (merge base) · 이 파일 없음
---
-### D-7. 드래그 앤 드롭으로 열기 — **코드 완료 · 화면 확인 남음** (2026-09-09)
+### D-7. 드래그 앤 드롭으로 열기 — **완료** (2026-09-09)
탐색기에서 파일·폴더를 끌어다 놓으면 그 자리에서 비교가 열린다.
@@ -212,8 +212,31 @@ BASE 머리글에 그렇게 적었다 - `BASE (merge base) · 이 파일 없음
가고 해당 탭이 켜진다. 화면 아무 데나 놓으면 이 판단을 타고, 왼쪽·오른쪽 경로 칸에 바로 놓으면
그 칸만 채운다.
-화면에서 실제로 끌어다 놓는 확인은 아직 못 했다. 작업 중 컴퓨터가 잠겨 탐색기에서
-끄는 동작을 만들 수 없었다. 잠금이 풀리면 확인한다.
+**실제로 탐색기에서 끌어다 놓아 보니 세 가지가 걸렸다.** 코드만 보고는 알 수 없는 것들이다.
+
+① 경로 칸 위에 놓으면 아무 일도 일어나지 않았다.
+폴더 비교의 경로 칸은 `TextBox` 인데, `TextBoxBase` 의 클래스 처리기가 `DragOver`·`Drop` 을
+먼저 먹는다. 그쪽은 글자 끌어다 놓기만 알아서 파일 목록은 버리고 `Handled` 로 막아 버린다.
+터널링 쪽(`PreviewDragOver`·`PreviewDrop`)으로 옮겨 클래스 처리기보다 먼저 받게 고쳤다.
+
+② 파일 비교 화면의 경로 글자는 놓을 자리 자체가 없었다.
+`TextBlock` 은 `Background` 가 없으면 히트 테스트에 안 잡힌다. `Background="Transparent"` 를 줬다.
+
+③ 칸에 놓아도 다시 견주지 않았다. 칸 값만 바뀌고 화면은 옛 파일을 그대로 보여 줬다 -
+"놓았는데 아무 일도 없다"로 읽힌다. `HomeViewModel.DropFile` 과 `FolderViewModel.DropFolder` 를
+만들어 넣은 뒤 바로 다시 견주게 했다. 폴더는 양쪽이 다 찼을 때만 견준다.
+
+**파일 하나씩 끌어다 놓아 짝을 만들 수 있게 했다.** 그 전에는 두 번째 파일이 첫 번째를 밀어내
+아무리 놓아도 왼쪽만 바뀌었다. 왼쪽만 차 있고 오른쪽이 비어 있으면 오른쪽을 채운다.
+
+**확인한 것**
+
+| 놓은 것 | 결과 |
+|---|---|
+| 폴더를 왼쪽·오른쪽 칸에 하나씩 | 두 칸이 차고 곧바로 비교가 돌았다 (`전체 4개 · 다름 1 · 왼쪽만 1 · 오른쪽만 1 · 같음 1`) |
+| 폴더를 화면 몸통에 | 왼쪽 칸에 들어갔다 |
+| 파일을 폴더 비교 몸통에 | 파일 비교 탭으로 넘어가고 BASE 에 들어갔다 |
+| 그 뒤 파일을 하나 더 | LOCAL 에 들어가고 짝이 맞춰졌다 (`총 8 라인 · 차이 2 라인`) |
---
diff --git a/src/MergeHub/ViewModels/FolderViewModel.cs b/src/MergeHub/ViewModels/FolderViewModel.cs
index 2148f0e..feeac81 100644
--- a/src/MergeHub/ViewModels/FolderViewModel.cs
+++ b/src/MergeHub/ViewModels/FolderViewModel.cs
@@ -343,6 +343,23 @@ namespace MergeHub.ViewModels
private CancellationTokenSource? _compareCancel;
+ ///
+ /// 끌어다 놓은 폴더를 한쪽 칸에 넣고, 양쪽이 다 차면 바로 견준다.
+ ///
+ /// 탐색기 우클릭으로 넘어오는 길과 같게 맞춘 것이다 - 두 칸이 다 찼는데도
+ /// [비교]를 한 번 더 눌러야 하면 놓은 보람이 없다.
+ ///
+ public void DropFolder(string folder, bool left)
+ {
+ if (string.IsNullOrWhiteSpace(folder)) return;
+
+ if (left) LeftFolder = folder;
+ else RightFolder = folder;
+
+ if (Directory.Exists(LeftFolder) && Directory.Exists(RightFolder)) _ = CompareAsync();
+ }
+
+
// ================= 폴더 전체 검색 =================
/// 찾은 줄. 파일 차례로 늘어선다.
diff --git a/src/MergeHub/ViewModels/HomeViewModel.cs b/src/MergeHub/ViewModels/HomeViewModel.cs
index dec624c..5bb71a6 100644
--- a/src/MergeHub/ViewModels/HomeViewModel.cs
+++ b/src/MergeHub/ViewModels/HomeViewModel.cs
@@ -1444,6 +1444,24 @@ namespace MergeHub.ViewModels
}
}
+ ///
+ /// 끌어다 놓은 파일을 한쪽 칸에 넣고 바로 다시 견준다.
+ ///
+ /// 칸 값만 바꾸고 두면 화면은 옛 파일을 그대로 보여 준다 - "놓았는데 아무 일도 없다"로 읽힌다.
+ /// 파일 고르기 단추와 같은 길(RequestPlainCompare)로 보내는 까닭은 그 길이
+ /// Git 모드를 끄는 것까지 함께 하기 때문이다. 저장소를 열어 둔 채로 파일을 끌어다 놓으면
+ /// 사용자가 보고 싶은 것은 그 두 파일이지 커밋 이력이 아니다.
+ ///
+ public void DropFile(string path, bool left)
+ {
+ if (string.IsNullOrWhiteSpace(path)) return;
+
+ var newLeft = left ? path : LeftFile;
+ var newRight = left ? RightFile : path;
+
+ _workspace.RequestPlainCompare(newLeft, newRight);
+ }
+
// ================= 결과 내보내기 =================
private bool CanExportReport() => Lines.Count > 0;
diff --git a/src/MergeHub/Views/FolderView.xaml b/src/MergeHub/Views/FolderView.xaml
index 6df4382..487d386 100644
--- a/src/MergeHub/Views/FolderView.xaml
+++ b/src/MergeHub/Views/FolderView.xaml
@@ -102,14 +102,14 @@
@@ -302,40 +302,70 @@
찾은 줄. 검색하기 전에는 접혀 있어 목록이 자리를 다 쓴다.
높이를 묶어 두는 까닭 - 결과가 수천 줄이어도 목록을 화면 밖으로 밀면 안 된다.
-->
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/MergeHub/Views/FolderView.xaml.cs b/src/MergeHub/Views/FolderView.xaml.cs
index ff6ee59..015db85 100644
--- a/src/MergeHub/Views/FolderView.xaml.cs
+++ b/src/MergeHub/Views/FolderView.xaml.cs
@@ -139,7 +139,15 @@ namespace MergeHub.Views
e.Handled = true;
}
- /// 왼쪽·오른쪽 칸에 바로 놓으면 그 자리에만 들어간다.
+ ///
+ /// 왼쪽·오른쪽 칸에 바로 놓으면 그 자리에만 들어간다.
+ ///
+ /// XAML 에서 PreviewDrop 으로 받는 까닭 - 경로 칸이 TextBox 라서
+ /// TextBoxBase 의 클래스 처리기가 DragOver·Drop 을 먼저 먹는다.
+ /// 그쪽은 글자 끌어다 놓기만 알아서 파일 목록은 버리고 Handled 로 막아 버린다.
+ /// 실제로 화면에서 칸 위에 놓아 봤더니 아무 일도 일어나지 않았다.
+ /// 터널링(Preview)은 클래스 처리기보다 먼저 도므로 이쪽이 먼저 받는다.
+ ///
private void LeftFolder_Drop(object sender, DragEventArgs e) => DropIntoSlot(e, left: true);
private void RightFolder_Drop(object sender, DragEventArgs e) => DropIntoSlot(e, left: false);
@@ -154,9 +162,6 @@ namespace MergeHub.Views
if (folder.Length == 0) folder = Services.PathUtil.FolderOfFile(paths[0]);
if (folder.Length == 0) return;
- if (left) vm.LeftFolder = folder;
- else vm.RightFolder = folder;
-
// 두 개를 한꺼번에 놓았으면 나머지 하나는 반대쪽에 넣는다.
if (paths.Length > 1)
{
@@ -170,10 +175,13 @@ namespace MergeHub.Views
}
}
+ // 넣고 나서 양쪽이 다 찼으면 그 자리에서 견준다.
+ vm.DropFolder(folder, left);
+
e.Handled = true;
}
private static string[]? DroppedPaths(DragEventArgs e) =>
e.Data.GetDataPresent(DataFormats.FileDrop) ? e.Data.GetData(DataFormats.FileDrop) as string[] : null;
}
-}
\ No newline at end of file
+}
diff --git a/src/MergeHub/Views/HomeView.xaml b/src/MergeHub/Views/HomeView.xaml
index babef09..f037f14 100644
--- a/src/MergeHub/Views/HomeView.xaml
+++ b/src/MergeHub/Views/HomeView.xaml
@@ -386,6 +386,7 @@
diff --git a/src/MergeHub/Views/HomeView.xaml.cs b/src/MergeHub/Views/HomeView.xaml.cs
index 31d82c4..2ac4cda 100644
--- a/src/MergeHub/Views/HomeView.xaml.cs
+++ b/src/MergeHub/Views/HomeView.xaml.cs
@@ -936,6 +936,16 @@ namespace MergeHub.Views
if (DataContext is not HomeViewModel vm) return;
if (DroppedPaths(e) is not { Length: > 0 } paths) return;
+ // 파일 하나를 놓았는데 왼쪽만 차 있으면 오른쪽을 채운다.
+ // 그러지 않으면 하나씩 끌어다 놓아서는 짝을 만들 수 없다 - 두 번째가 첫 번째를 밀어낸다.
+ if (paths.Length == 1 && System.IO.File.Exists(paths[0]) &&
+ !string.IsNullOrWhiteSpace(vm.LeftFile) && string.IsNullOrWhiteSpace(vm.RightFile))
+ {
+ vm.DropFile(paths[0], left: false);
+ e.Handled = true;
+ return;
+ }
+
vm.Workspace.RouteDroppedPaths(paths);
e.Handled = true;
}
@@ -958,9 +968,6 @@ namespace MergeHub.Views
return;
}
- if (left) vm.LeftFile = paths[0];
- else vm.RightFile = paths[0];
-
// 두 개를 한꺼번에 놓았으면 나머지 하나는 반대쪽에 넣는다.
if (paths.Length > 1 && !System.IO.Directory.Exists(paths[1]))
{
@@ -968,6 +975,9 @@ namespace MergeHub.Views
else vm.LeftFile = paths[1];
}
+ // 칸 값만 바꾸면 화면은 옛 파일을 그대로 보여 준다. 넣고 바로 다시 견준다.
+ vm.DropFile(paths[0], left);
+
e.Handled = true;
}