diff --git a/src/SheetMe.Designer/Diagnostics/DbSmoke.cs b/src/SheetMe.Designer/Diagnostics/DbSmoke.cs
index 05598ed..dafc25d 100644
--- a/src/SheetMe.Designer/Diagnostics/DbSmoke.cs
+++ b/src/SheetMe.Designer/Diagnostics/DbSmoke.cs
@@ -696,7 +696,8 @@ public static class DbSmoke
System.Windows.Input.Keyboard.ClearFocus();
box.RaiseEvent(new System.Windows.RoutedEventArgs(System.Windows.UIElement.LostFocusEvent));
DrainDispatcher();
- Check("포커스를 잃으면 닫힌다", openBeforeBlur && !popup.IsOpen);
+ Check("포커스를 잃으면 닫힌다", openBeforeBlur && !popup.IsOpen,
+ $"blur 전 열림={openBeforeBlur}, blur 후 열림={popup.IsOpen}");
// ⑦ 바깥 클릭으로 닫히는 설정인지
Check("바깥 클릭으로 닫히는 설정(StaysOpen=False)", !popup.StaysOpen);
diff --git a/src/SheetMe.Designer/Views/QueryEditorWindow.xaml b/src/SheetMe.Designer/Views/QueryEditorWindow.xaml
index 457b05a..4c1feaa 100644
--- a/src/SheetMe.Designer/Views/QueryEditorWindow.xaml
+++ b/src/SheetMe.Designer/Views/QueryEditorWindow.xaml
@@ -23,11 +23,79 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -83,22 +151,22 @@
-
-
-
-
@@ -115,13 +183,12 @@
Margin="0,0,0,10"/>
-
-
+
+
+ ToolTip="예약어를 대문자로 바꾸고 절마다 줄을 나눕니다. 문자열·치환 변수는 건드리지 않습니다."/>
-
-
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
-
@@ -173,9 +242,11 @@
-
-
+
+
+
@@ -203,9 +274,9 @@
CompletionPopup.IsOpen = false));
+ new ScrollChangedEventHandler((_, _) => RepositionCompletion()));
// 창을 벗어나면 목록이 다른 창 위에 떠 있게 된다
Deactivated += (_, _) => CompletionPopup.IsOpen = false;
@@ -228,6 +230,29 @@ public partial class QueryEditorWindow : Window
private void OnSqlLostFocus(object sender, RoutedEventArgs e) => CompletionPopup.IsOpen = false;
+ ///
+ /// 스크롤로 자리가 움직였을 때 목록을 새 자리에 다시 놓는다.
+ ///
+ /// WPF Popup 은 열려 있는 동안 Placement 를 다시 계산하지 않으므로 닫았다 다시 연다.
+ /// 걸려 있던 낱말을 커서가 벗어났으면 그때는 닫는다 — 더 이상 유효한 목록이 아니다.
+ ///
+ private void RepositionCompletion()
+ {
+ if (!CompletionPopup.IsOpen)
+ {
+ return;
+ }
+ var caret = SqlBox.CaretIndex;
+ if (caret < completionStart || caret > completionEnd)
+ {
+ CompletionPopup.IsOpen = false;
+ return;
+ }
+ CompletionPopup.IsOpen = false;
+ PlaceCompletionPopup();
+ CompletionPopup.IsOpen = true;
+ }
+
private IEnumerable CandidatesFor(SqlCompletionQuery query)
{
switch (query.Context)