diff --git a/src/SheetMe.Designer/Controls/DialogChrome.cs b/src/SheetMe.Designer/Controls/DialogChrome.cs
new file mode 100644
index 0000000..02aec05
--- /dev/null
+++ b/src/SheetMe.Designer/Controls/DialogChrome.cs
@@ -0,0 +1,90 @@
+using System.Windows;
+using System.Windows.Input;
+
+namespace SheetMe.Designer.Controls;
+
+///
+/// 대화상자 크롬을 켠다 — ThemedDialogWindow 스타일이 스타일 세터로 걸어 준다.
+///
+/// 왜 첨부 속성인가. 창 12종에 같은 타이틀바를 주려면 이 필요한데,
+/// 템플릿 안의 닫기 버튼은 Click 핸들러를 가질 수 없다(템플릿은 코드비하인드가 없다).
+/// 그래서 표준 를 쓰고, 그 명령을 받을
+/// 을 여기서 창에 달아 준다. 창마다 코드를 넣지 않아도 된다.
+///
+/// 최대화 보정도 함께 건다. WindowStyle=None 인 창은 최대화하는 순간
+/// 작업표시줄을 덮는다(메인 창에서 실제로 겪은 결함이다). 대화상자 대부분이 크기 조절 가능이라
+/// 타이틀바를 더블클릭하면 그 상태에 들어갈 수 있다 — 크롬을 켜는 이 자리에서 같이 막는다.
+///
+public static class DialogChrome
+{
+ #region Attached Properties
+ /// 크롬 사용 여부 — 스타일이 True 로 세팅한다
+ public static readonly DependencyProperty EnabledProperty =
+ DependencyProperty.RegisterAttached(
+ "Enabled", typeof(bool), typeof(DialogChrome),
+ new PropertyMetadata(false, OnEnabledChanged));
+
+ public static void SetEnabled(DependencyObject element, bool value)
+ => element.SetValue(EnabledProperty, value);
+
+ public static bool GetEnabled(DependencyObject element)
+ => (bool)element.GetValue(EnabledProperty);
+ #endregion
+
+ #region Methods
+ private static void OnEnabledChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
+ {
+ if (sender is not Window window || e.NewValue is not true)
+ {
+ return;
+ }
+ // 같은 창에 두 번 걸리지 않게 한다 — 스타일이 다시 적용되는 경로가 있다
+ foreach (CommandBinding existing in window.CommandBindings)
+ {
+ if (existing.Command == SystemCommands.CloseWindowCommand)
+ {
+ return;
+ }
+ }
+ // 크롬은 창마다 새로 만든다. WindowChrome 은 Freezable 이고 창에 붙으면서
+ // 스스로 속성을 고치므로, 한 인스턴스를 여러 창이 나눠 쓰면 두 번째 창부터
+ // "읽기 전용 상태라 속성을 설정할 수 없습니다"로 죽는다.
+ // 그래서 XAML 스타일 세터로는 줄 수 없다(세터 값은 한 번 평가돼 공유된다).
+ //
+ // CaptionHeight 36 = 타이틀바 높이와 같아야 그 띠를 잡고 창을 끌 수 있다.
+ // GlassFrameThickness 0,0,0,1 = DWM 그림자 유지.
+ // ResizeBorderThickness 6 은 ResizeMode 가 허용할 때만 실제로 동작한다.
+ System.Windows.Shell.WindowChrome.SetWindowChrome(window, new System.Windows.Shell.WindowChrome
+ {
+ CaptionHeight = 36,
+ ResizeBorderThickness = new Thickness(6),
+ GlassFrameThickness = new Thickness(0, 0, 0, 1),
+ CornerRadius = new CornerRadius(0),
+ UseAeroCaptionButtons = false,
+ });
+
+ window.CommandBindings.Add(new CommandBinding(
+ SystemCommands.CloseWindowCommand,
+ (_, args) =>
+ {
+ // 창의 X 를 누른 것과 같아야 한다 — DialogResult 를 건드리지 않으므로
+ // ShowDialog 는 false 를 돌려주고, 호출부의 '취소' 경로가 그대로 탄다
+ SystemCommands.CloseWindow(window);
+ args.Handled = true;
+ }));
+
+ // 크기 조절 가능한 창만 최대화될 수 있다 — 그때 작업표시줄을 덮지 않게 한다
+ if (window.ResizeMode is ResizeMode.CanResize or ResizeMode.CanResizeWithGrip)
+ {
+ if (window.IsInitialized)
+ {
+ Services.MaximizeToWorkArea.Attach(window);
+ }
+ else
+ {
+ window.SourceInitialized += (_, _) => Services.MaximizeToWorkArea.Attach(window);
+ }
+ }
+ }
+ #endregion
+}
diff --git a/src/SheetMe.Designer/Diagnostics/DialogShots.cs b/src/SheetMe.Designer/Diagnostics/DialogShots.cs
index 22f255c..d3a0f68 100644
--- a/src/SheetMe.Designer/Diagnostics/DialogShots.cs
+++ b/src/SheetMe.Designer/Diagnostics/DialogShots.cs
@@ -390,18 +390,26 @@ public static class DialogShots
// 레이아웃·비동기 로딩(Loaded 핸들러)이 한 바퀴 돌게 한다
Pump();
- // 창 자체를 렌더한다 — Content 만 찍으면 Window.Background(B.AppBg)가 빠져 투명이 되고,
- // PNG 에서 검정으로 저장돼 "다크처럼 보이는" 착시가 생긴다(라이트 결함이 가려진다).
+ // 창 전체를 찍는다 — Content 만 찍으면 타이틀바가 통째로 빠진다.
+ //
+ // 전에는 Content 를 찍었다. 그래서 창 크롬을 통일하기 전까지 이 진단은
+ // "열한 창이 윈도우 기본 타이틀바를 달고 뜬다"는 사실을 한 번도 보여 준 적이 없었다 —
+ // 고쳐야 할 바로 그 부분에 눈이 없었던 셈이다. 이제 커스텀 타이틀바는 창의 Template
+ // 안에 있으므로 Content 만 찍으면 여전히 안 보인다.
+ //
+ // 배경을 먼저 칠하는 것은 그대로 둔다 — 투명 픽셀이 PNG 에서 검정으로 저장되면
+ // 라이트 테마 결함이 "다크처럼 보이는" 착시에 가려진다.
var content = (FrameworkElement)window.Content;
- var width = (int)Math.Ceiling(content.ActualWidth > 0 ? content.ActualWidth : window.Width);
- var height = (int)Math.Ceiling(content.ActualHeight > 0 ? content.ActualHeight : window.Height);
+ var root = (FrameworkElement?)window.Template?.FindName("PART_Root", window) ?? content;
+ var width = (int)Math.Ceiling(window.ActualWidth > 0 ? window.ActualWidth : window.Width);
+ var height = (int)Math.Ceiling(window.ActualHeight > 0 ? window.ActualHeight : window.Height);
var bitmap = new RenderTargetBitmap(Math.Max(1, width), Math.Max(1, height), 96, 96, PixelFormats.Pbgra32);
var drawing = new DrawingVisual();
using (var context = drawing.RenderOpen())
{
context.DrawRectangle(window.Background ?? Brushes.Transparent, null, new Rect(0, 0, width, height));
- context.DrawRectangle(new VisualBrush(content) { Stretch = Stretch.None, AlignmentX = AlignmentX.Left, AlignmentY = AlignmentY.Top },
+ context.DrawRectangle(new VisualBrush(root) { Stretch = Stretch.None, AlignmentX = AlignmentX.Left, AlignmentY = AlignmentY.Top },
null, new Rect(0, 0, width, height));
}
bitmap.Render(drawing);
diff --git a/src/SheetMe.Designer/Themes/DesignerTheme.xaml b/src/SheetMe.Designer/Themes/DesignerTheme.xaml
index 68c080f..fe94043 100644
--- a/src/SheetMe.Designer/Themes/DesignerTheme.xaml
+++ b/src/SheetMe.Designer/Themes/DesignerTheme.xaml
@@ -1404,4 +1404,68 @@
+
+
+
diff --git a/src/SheetMe.Designer/Views/DataSourceResultDialogView.xaml b/src/SheetMe.Designer/Views/DataSourceResultDialogView.xaml
index 569c476..5cf8c49 100644
--- a/src/SheetMe.Designer/Views/DataSourceResultDialogView.xaml
+++ b/src/SheetMe.Designer/Views/DataSourceResultDialogView.xaml
@@ -4,7 +4,7 @@
Title="데이터소스 조회 결과" Width="980" Height="640"
MinWidth="760" MinHeight="440"
WindowStartupLocation="CenterOwner" ShowInTaskbar="False"
- Style="{StaticResource ThemedWindow}">
+ Style="{StaticResource ThemedDialogWindow}">
-
+
diff --git a/src/SheetMe.Designer/Views/DataTableFieldDialogView.xaml b/src/SheetMe.Designer/Views/DataTableFieldDialogView.xaml
index cdfd2d6..e7d30cb 100644
--- a/src/SheetMe.Designer/Views/DataTableFieldDialogView.xaml
+++ b/src/SheetMe.Designer/Views/DataTableFieldDialogView.xaml
@@ -3,7 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="데이터 필드 배선" Width="560" Height="520"
WindowStartupLocation="CenterOwner" ShowInTaskbar="False"
- Style="{StaticResource ThemedWindow}">
+ Style="{StaticResource ThemedDialogWindow}">
diff --git a/src/SheetMe.Designer/Views/FontManagerDialogView.xaml b/src/SheetMe.Designer/Views/FontManagerDialogView.xaml
index ef22180..7599731 100644
--- a/src/SheetMe.Designer/Views/FontManagerDialogView.xaml
+++ b/src/SheetMe.Designer/Views/FontManagerDialogView.xaml
@@ -3,7 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="폰트 일괄 변경" Width="620" Height="560" MinWidth="520" MinHeight="420"
WindowStartupLocation="CenterOwner" ShowInTaskbar="False"
- Style="{StaticResource ThemedWindow}">
+ Style="{StaticResource ThemedDialogWindow}">
@@ -23,7 +23,10 @@
-
+
+
diff --git a/src/SheetMe.Designer/Views/LayerTypeFilterDialog.xaml b/src/SheetMe.Designer/Views/LayerTypeFilterDialog.xaml
index 317a98e..91012af 100644
--- a/src/SheetMe.Designer/Views/LayerTypeFilterDialog.xaml
+++ b/src/SheetMe.Designer/Views/LayerTypeFilterDialog.xaml
@@ -4,7 +4,7 @@
xmlns:ctl="clr-namespace:SheetMe.Designer.Controls"
Title="타입으로 거르기" Width="380" Height="520"
WindowStartupLocation="CenterOwner" ShowInTaskbar="False"
- Style="{StaticResource ThemedWindow}">
+ Style="{StaticResource ThemedDialogWindow}">
@@ -15,7 +15,7 @@
-
+
diff --git a/src/SheetMe.Designer/Views/MaskPickerDialogView.xaml b/src/SheetMe.Designer/Views/MaskPickerDialogView.xaml
index faf2699..50e49b5 100644
--- a/src/SheetMe.Designer/Views/MaskPickerDialogView.xaml
+++ b/src/SheetMe.Designer/Views/MaskPickerDialogView.xaml
@@ -3,7 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="마스크 편집" Width="620" Height="620"
WindowStartupLocation="CenterOwner" ShowInTaskbar="False"
- Style="{StaticResource ThemedWindow}">
+ Style="{StaticResource ThemedDialogWindow}">
diff --git a/src/SheetMe.Designer/Views/RegisterSheetDialogView.xaml b/src/SheetMe.Designer/Views/RegisterSheetDialogView.xaml
index 62a8493..0562fbd 100644
--- a/src/SheetMe.Designer/Views/RegisterSheetDialogView.xaml
+++ b/src/SheetMe.Designer/Views/RegisterSheetDialogView.xaml
@@ -3,7 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="신규 서식 등록" Width="420" SizeToContent="Height"
WindowStartupLocation="CenterOwner" ShowInTaskbar="False" ResizeMode="NoResize"
- Style="{StaticResource ThemedWindow}">
+ Style="{StaticResource ThemedDialogWindow}">
@@ -26,7 +26,7 @@
TextWrapping="Wrap" Foreground="{DynamicResource B.Muted}" FontSize="11" Margin="0,10,0,0"/>
-
+
diff --git a/src/SheetMe.Designer/Views/SheetHistoryDialogView.xaml b/src/SheetMe.Designer/Views/SheetHistoryDialogView.xaml
index f86d9ce..4ccdcab 100644
--- a/src/SheetMe.Designer/Views/SheetHistoryDialogView.xaml
+++ b/src/SheetMe.Designer/Views/SheetHistoryDialogView.xaml
@@ -3,14 +3,14 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="서식 수정이력" Width="560" Height="520" MinWidth="480" MinHeight="380"
WindowStartupLocation="CenterOwner" ShowInTaskbar="False"
- Style="{StaticResource ThemedWindow}">
+ Style="{StaticResource ThemedDialogWindow}">
-
diff --git a/src/SheetMe.Designer/Views/TagPickerDialogView.xaml b/src/SheetMe.Designer/Views/TagPickerDialogView.xaml
index c1abddd..bdcf60a 100644
--- a/src/SheetMe.Designer/Views/TagPickerDialogView.xaml
+++ b/src/SheetMe.Designer/Views/TagPickerDialogView.xaml
@@ -4,7 +4,7 @@
xmlns:ctl="clr-namespace:SheetMe.Designer.Controls"
Title="태그 선택" Width="1080" Height="700" MinWidth="900" MinHeight="560"
WindowStartupLocation="CenterOwner" ShowInTaskbar="False"
- Style="{StaticResource ThemedWindow}">
+ Style="{StaticResource ThemedDialogWindow}">