순정 MessageBox 를 앱 테마 대화상자로 교체 (53곳 중 49곳)
다크 테마에서 흰 시스템 창이 튀어나오던 알림을 자체 창(MessageDialogView)으로 바꿨다. 앱 셸과 같은 커스텀 타이틀바(36px) + B.Surface 본문 + 성격 아이콘 + 우측 버튼 줄. 폭 440 고정, 내용에 따라 높이 자동, 긴 예외는 스크롤로 흡수한다. 진입점은 DialogService 정적 메서드 4개로 모았다 — Notify / Confirm / ConfirmWithCancel / ShowError. MessageBox 는 Win32 호출이라 아무 데서나 되지만 WPF 창은 아니다. 교체로 새로 생기는 제약 셋을 DialogService 한곳에서 막는다. - 진단 모드에서는 창을 만들지 않고 기각 기본값을 즉시 돌려준다. 스모크는 무인 실행이라 모달이 하나라도 뜨면 타임아웃 없이 영원히 멈춘다 — 실제로 편집 스모크가 지나는 경로에 붙여넣기·개명 가드가 있다. 규약을 스모크 검사 3건으로 고정했다. - UI 스레드가 아니면 Dispatcher 로 넘긴다. - 소유 창은 '살아 있는 것'만 건다. 아직 안 보였거나 이미 닫힌 창을 Owner 로 주면 예외이고, 진단 렌더러가 도는 동안 MainWindow 가 닫힌 창을 가리킬 수 있다. App.xaml.cs 4곳은 다르게 처리했다. - 기동 실패(:49)·예외 폭주(:82)·복구 안내(:89) 3곳은 순정 유지. 창이 없는 시점이라 자체 창을 띄우면 종료코드가 유실되고, 이미 예외가 터진 자리에서 WPF 창을 새로 만들면 같은 핸들러로 재진입한다. 이유를 각 자리에 주석으로 남겼다. 덤으로 :89 는 e.Handled 를 알림보다 먼저 세우도록 순서를 바로잡았다 — 알림이 던지면 '복구 가능한 예외'가 하드 크래시로 바뀐다. - 알 수 없는 진단 옵션(:179)은 알림을 없앴다. 옵션 오타 하나로 무인 실행이 멈추던 자리다. 함께 고친 것 — Primary 버튼 스타일. 공유 버튼 템플릿의 호버 트리거가 TargetName 으로 채움을 회색으로 덮는데(TargetName 트리거는 TemplateBinding 을 이긴다) 글자는 흰색 그대로라, 라이트에서 마우스를 올리면 #F3F3F3 위 흰 글자 1.08:1 로 사라진다. 지금까지 Primary 사용처가 0건이라 드러난 적이 없었고 이 창이 첫 사용이다. 전용 템플릿 + 채움 호버·누름 토큰 2종 신설. 신설 토큰: B.Warning / B.Danger(라이트는 다크값을 못 쓴다 — 앰버 #E0A33A 는 흰 면 위 2.22:1 로 아이콘 기준 3:1 도 미달), B.AccentFillHover / B.AccentFillPressed. 전부 양 테마에 동시 추가. Lucide 아이콘 4종(info·circle-alert·triangle-alert·circle-help) 추가. 바꾸지 않은 것: 예외 원문. 18곳을 ShowError 로 수렴시키면 화면에서 ex.Message 가 오류코드+로그로 대체되는 동작 변경이 된다 — 요청은 시각 변경이라 문구·정보량을 그대로 뒀다. 남는 시스템 대화상자: 인쇄(PrintDialog)와 파일 열기/저장 — OS 셸 대화상자라 대상이 아니다. 진단 렌더러에 알림 5종(오류·경고·확인·저장확인·정보)을 등록해 라이트/다크 10장이 자동으로 남는다. 회귀: 테스트 124/124, 편집 스모크 실패 0, DB 왕복 1,271건 diff 0/예외 0, 종이 렌더 P062 바이트 동일. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
bd0d055e0d
commit
604f8f7d1b
@@ -4,6 +4,8 @@ using System.Windows.Media;
|
||||
using SheetMe.Core.Serialization;
|
||||
using SheetMe.Designer.ViewModels;
|
||||
|
||||
using SheetMe.Designer.Services;
|
||||
|
||||
namespace SheetMe.Designer.Views;
|
||||
|
||||
/// <summary>
|
||||
@@ -47,19 +49,19 @@ public partial class FontManagerDialogView : Window
|
||||
{
|
||||
if (targets.Count == 0)
|
||||
{
|
||||
MessageBox.Show("변경할 조합을 선택하세요.", "폰트 일괄 변경");
|
||||
DialogService.Notify(DialogKind.Warning, "폰트 일괄 변경", "변경할 조합을 선택하세요.", owner: this);
|
||||
return;
|
||||
}
|
||||
var family = FamilyBox.Text.Trim();
|
||||
if (family.Length == 0)
|
||||
{
|
||||
MessageBox.Show("글꼴명을 입력하세요.", "폰트 일괄 변경");
|
||||
DialogService.Notify(DialogKind.Warning, "폰트 일괄 변경", "글꼴명을 입력하세요.", owner: this);
|
||||
return;
|
||||
}
|
||||
if (!double.TryParse(SizeBox.Text.Trim(), NumberStyles.Number, CultureInfo.InvariantCulture, out var sizePt)
|
||||
|| sizePt <= 0 || sizePt > 200)
|
||||
{
|
||||
MessageBox.Show("크기(pt)를 올바르게 입력하세요.", "폰트 일괄 변경");
|
||||
DialogService.Notify(DialogKind.Warning, "폰트 일괄 변경", "크기(pt)를 올바르게 입력하세요.", owner: this);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
<Window x:Class="SheetMe.Designer.Views.MessageDialogView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:shell="clr-namespace:System.Windows.Shell;assembly=PresentationFramework"
|
||||
Title="알림" Width="440" SizeToContent="Height" MaxHeight="620"
|
||||
WindowStyle="None" ResizeMode="NoResize" ShowInTaskbar="False"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
FontFamily="Malgun Gothic" FontSize="13"
|
||||
Background="{DynamicResource B.Surface}"
|
||||
Style="{StaticResource ThemedWindow}">
|
||||
<!--
|
||||
알림·확인 대화상자 — 순정 Win32 MessageBox 대체.
|
||||
|
||||
Style="{StaticResource ThemedWindow}" 를 반드시 명시한다. WPF 는 암시 스타일을
|
||||
'정확한 런타임 타입'으로만 찾으므로 Window 파생 클래스에는 <Style TargetType="Window"> 가
|
||||
걸리지 않는다 — 예전에 대화상자 8종이 전부 흰 배경으로 나오던 결함이 그것이었다.
|
||||
|
||||
AllowsTransparency 는 켜지 않는다: 레이어드 윈도우가 되면 ClearType 이 꺼져 13px 한글이
|
||||
뭉개지고, 진단 렌더러가 찍는 PNG 배경이 알파가 되어 라이트 결함이 가려진다.
|
||||
-->
|
||||
|
||||
<!-- 앱 셸과 같은 크롬. GlassFrameThickness 0,0,0,1 = DWM 그림자 유지, ResizeBorder 0 = 크기 고정 -->
|
||||
<shell:WindowChrome.WindowChrome>
|
||||
<shell:WindowChrome CaptionHeight="36" ResizeBorderThickness="0"
|
||||
GlassFrameThickness="0,0,0,1" CornerRadius="0"
|
||||
UseAeroCaptionButtons="False"/>
|
||||
</shell:WindowChrome.WindowChrome>
|
||||
|
||||
<Border BorderBrush="{DynamicResource B.Line2}" BorderThickness="1"
|
||||
Background="{DynamicResource B.Surface}">
|
||||
<DockPanel>
|
||||
|
||||
<!-- 타이틀바 — 드래그는 WindowChrome 이 처리하므로 DragMove 핸들러가 없다 -->
|
||||
<Border DockPanel.Dock="Top" Height="36" Background="{DynamicResource B.Titlebar}"
|
||||
BorderBrush="{DynamicResource B.Line}" BorderThickness="0,0,0,1">
|
||||
<Grid>
|
||||
<TextBlock x:Name="CaptionText" Margin="14,0,52,0" VerticalAlignment="Center"
|
||||
FontSize="12" Foreground="{DynamicResource B.Muted}"
|
||||
TextTrimming="CharacterEllipsis"/>
|
||||
<!-- IsHitTestVisibleInChrome 필수 — 빠지면 클릭이 창 드래그로 먹혀 닫을 수 없다 -->
|
||||
<Button x:Name="CloseButton" Style="{StaticResource CloseBtn}" Height="36"
|
||||
HorizontalAlignment="Right" IsTabStop="False" Click="OnDismissClick"
|
||||
shell:WindowChrome.IsHitTestVisibleInChrome="True" ToolTip="닫기">
|
||||
<TextBlock Text="" FontFamily="Segoe MDL2 Assets" FontSize="10"/>
|
||||
</Button>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- 버튼 줄 — 순서는 저장소 관행대로 [보조] … [긍정][부정] -->
|
||||
<Border x:Name="Footer" DockPanel.Dock="Bottom" Padding="20,12"
|
||||
BorderBrush="{DynamicResource B.Line}" BorderThickness="0">
|
||||
<DockPanel LastChildFill="False">
|
||||
<Button x:Name="CopyButton" DockPanel.Dock="Left" Style="{StaticResource Subtle}"
|
||||
Content="내용 복사" Height="32" VerticalAlignment="Center"
|
||||
Visibility="Collapsed" Click="OnCopyClick"/>
|
||||
<StackPanel DockPanel.Dock="Right" Orientation="Horizontal">
|
||||
<Button x:Name="AffirmButton" Style="{StaticResource Primary}"
|
||||
MinWidth="84" Height="32" Content="확인" Click="OnAffirmClick"/>
|
||||
<Button x:Name="DenyButton" MinWidth="84" Height="32" Margin="8,0,0,0"
|
||||
BorderBrush="{DynamicResource B.Line2}" Content="아니오"
|
||||
Visibility="Collapsed" Click="OnDenyClick"/>
|
||||
<Button x:Name="CancelButton" MinWidth="84" Height="32" Margin="8,0,0,0"
|
||||
BorderBrush="{DynamicResource B.Line2}" Content="취소"
|
||||
Visibility="Collapsed" Click="OnDismissClick"/>
|
||||
</StackPanel>
|
||||
</DockPanel>
|
||||
</Border>
|
||||
|
||||
<!--
|
||||
본문. 여백을 ScrollViewer 가 아니라 안쪽 DockPanel 에 둔다 — 그래야 스크롤바가
|
||||
창 오른쪽 끝에 붙고 글자만 좁아진다.
|
||||
가로 스크롤은 Disabled 여야 TextWrapping 이 실제로 동작한다.
|
||||
-->
|
||||
<ScrollViewer x:Name="BodyScroll" Focusable="False"
|
||||
VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled"
|
||||
ScrollChanged="OnBodyScrollChanged">
|
||||
<DockPanel Margin="20,18,20,14">
|
||||
<ContentControl x:Name="SeverityIcon" DockPanel.Dock="Left" IsTabStop="False"
|
||||
Focusable="False" VerticalAlignment="Top" Margin="0,1,14,0"/>
|
||||
<StackPanel>
|
||||
<!-- 굵게 하지 않는다 — Malgun Gothic 은 SemiBold 가 없어 합성되므로
|
||||
DPI·테마에 따라 렌더가 흔들린다. 크기와 색만으로 위계를 세운다. -->
|
||||
<TextBlock x:Name="HeadText" TextWrapping="Wrap"
|
||||
FontSize="13.5" LineHeight="21" LineStackingStrategy="BlockLineHeight"
|
||||
Foreground="{DynamicResource B.Ink}"/>
|
||||
<TextBlock x:Name="DetailText" TextWrapping="Wrap" Margin="0,8,0,0"
|
||||
FontSize="12.5" LineHeight="19" LineStackingStrategy="BlockLineHeight"
|
||||
Foreground="{DynamicResource B.Muted}" Visibility="Collapsed"/>
|
||||
</StackPanel>
|
||||
</DockPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
</DockPanel>
|
||||
</Border>
|
||||
</Window>
|
||||
@@ -0,0 +1,161 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using SheetMe.Designer.Controls;
|
||||
using SheetMe.Designer.Services;
|
||||
|
||||
namespace SheetMe.Designer.Views;
|
||||
|
||||
/// <summary>
|
||||
/// 알림·확인 대화상자 — 순정 Win32 MessageBox 대체.
|
||||
///
|
||||
/// 기각 의미론은 MessageBox 를 그대로 따른다: 닫기(X)·Alt+F4·Esc 는
|
||||
/// 확인 1개면 '확인', 예/아니오면 '아니오', 예/아니오/취소면 '취소'로 돌아간다.
|
||||
///
|
||||
/// <b><see cref="Window.DialogResult"/> 를 쓰지 않는다.</b> Show() 로 띄운 창에 대입하면
|
||||
/// InvalidOperationException 이고, 진단 렌더러(DialogShots)가 정확히 그 경로로 이 창을 찍는다.
|
||||
/// 같은 이유로 <c>Closing</c> 에서 <c>e.Cancel</c> 로 닫기를 막지도 않는다 —
|
||||
/// 렌더러가 <c>Close()</c> 로만 창을 정리하므로 취소되면 화면 밖 창이 살아남는다.
|
||||
/// </summary>
|
||||
public partial class MessageDialogView : Window
|
||||
{
|
||||
#region Member Fields
|
||||
private readonly string caption;
|
||||
private readonly string head;
|
||||
private readonly string? detail;
|
||||
private bool? answer;
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
/// <summary>사용자 응답 — 예=true / 아니오=false / 취소=null</summary>
|
||||
public bool? Answer => answer;
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// 공개 생성자 — 정적 헬퍼로 감싸지 말고 이 형태를 유지할 것.
|
||||
/// 진단 렌더러가 팩토리로 <c>new</c> 해서 라이트·다크 스냅샷을 찍는다(private 생성자면 편입 불가).
|
||||
/// </summary>
|
||||
public MessageDialogView(DialogKind kind, string caption, string head, string? detail,
|
||||
DialogButtons buttons, string yes = "예", string no = "아니오", bool destructive = false)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
this.caption = caption;
|
||||
this.head = head;
|
||||
this.detail = detail;
|
||||
|
||||
// 노트북 해상도에서 창이 화면을 덮지 않도록 한 번 더 조인다
|
||||
MaxHeight = Math.Min(620, SystemParameters.WorkArea.Height * 0.85);
|
||||
|
||||
CaptionText.Text = caption;
|
||||
HeadText.Text = head;
|
||||
DetailText.Text = detail ?? string.Empty;
|
||||
DetailText.Visibility = string.IsNullOrEmpty(detail) ? Visibility.Collapsed : Visibility.Visible;
|
||||
|
||||
var (icon, brushKey) = Visual(kind);
|
||||
// 색은 반드시 '키'로 넘긴다 — Brush 인스턴스를 대입하면 그 시점 값으로 굳어 테마 전환을 못 따라간다
|
||||
SeverityIcon.Content = LucideIcons.Icon(icon, 22, brushKey);
|
||||
// 오류만 복사 버튼을 노출한다 — 오류 코드를 전화로 불러 주던 실사용 경로
|
||||
CopyButton.Visibility = kind == DialogKind.Error ? Visibility.Visible : Visibility.Collapsed;
|
||||
|
||||
Configure(buttons, yes, no, destructive);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
/// <summary>성격 → (아이콘, 색 토큰)</summary>
|
||||
private static (string Icon, string BrushKey) Visual(DialogKind kind) => kind switch
|
||||
{
|
||||
DialogKind.Error => ("circle-alert", "B.Danger"),
|
||||
DialogKind.Warning => ("triangle-alert", "B.Warning"),
|
||||
DialogKind.Question => ("circle-help", "B.AccentText"),
|
||||
_ => ("info", "B.AccentText"),
|
||||
};
|
||||
|
||||
/// <summary>버튼 구성·기본 응답·초기 포커스</summary>
|
||||
private void Configure(DialogButtons buttons, string yes, string no, bool destructive)
|
||||
{
|
||||
switch (buttons)
|
||||
{
|
||||
case DialogButtons.YesNo:
|
||||
answer = false;
|
||||
AffirmButton.Content = yes;
|
||||
DenyButton.Content = no;
|
||||
DenyButton.Visibility = Visibility.Visible;
|
||||
DenyButton.IsCancel = true;
|
||||
break;
|
||||
|
||||
case DialogButtons.YesNoCancel:
|
||||
answer = null;
|
||||
AffirmButton.Content = yes;
|
||||
DenyButton.Content = no;
|
||||
DenyButton.Visibility = Visibility.Visible;
|
||||
CancelButton.Visibility = Visibility.Visible;
|
||||
CancelButton.IsCancel = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
answer = true;
|
||||
AffirmButton.Content = "확인";
|
||||
AffirmButton.IsCancel = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// 되돌리기 어려운 확인에서는 기본 버튼을 부정 쪽에 둔다 — Enter 한 번에 페이지가 지워지면 안 된다
|
||||
var defaultButton = destructive && DenyButton.Visibility == Visibility.Visible
|
||||
? DenyButton
|
||||
: AffirmButton;
|
||||
defaultButton.IsDefault = true;
|
||||
Loaded += (_, _) => defaultButton.Focus();
|
||||
}
|
||||
|
||||
private void OnAffirmClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
answer = true;
|
||||
Close();
|
||||
}
|
||||
|
||||
private void OnDenyClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
answer = false;
|
||||
Close();
|
||||
}
|
||||
|
||||
/// <summary>닫기(X)·취소 — 생성자에서 정한 기각 기본값을 그대로 두고 닫는다</summary>
|
||||
private void OnDismissClick(object sender, RoutedEventArgs e) => Close();
|
||||
|
||||
/// <summary>본문이 넘칠 때만 버튼 줄 위에 구분선 — 창이 최대 높이에 걸렸다는 유일한 신호</summary>
|
||||
private void OnBodyScrollChanged(object sender, System.Windows.Controls.ScrollChangedEventArgs e)
|
||||
=> Footer.BorderThickness = new Thickness(0, BodyScroll.ScrollableHeight > 0.5 ? 1 : 0, 0, 0);
|
||||
|
||||
/// <summary>내용 복사 — MessageBox 의 Ctrl+C 동작 보존(오류 코드를 옮겨 적던 경로)</summary>
|
||||
private void OnCopyClick(object sender, RoutedEventArgs e) => CopyToClipboard();
|
||||
|
||||
protected override void OnKeyDown(KeyEventArgs e)
|
||||
{
|
||||
if (e.Key == Key.C && Keyboard.Modifiers == ModifierKeys.Control)
|
||||
{
|
||||
CopyToClipboard();
|
||||
e.Handled = true;
|
||||
return;
|
||||
}
|
||||
base.OnKeyDown(e);
|
||||
}
|
||||
|
||||
private void CopyToClipboard()
|
||||
{
|
||||
var text = string.IsNullOrEmpty(detail)
|
||||
? $"{caption}\n---\n{head}"
|
||||
: $"{caption}\n---\n{head}\n\n{detail}";
|
||||
try
|
||||
{
|
||||
Clipboard.SetText(text);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 클립보드는 다른 프로세스가 잠글 수 있다 — 복사 실패가 알림 자체를 막으면 안 된다
|
||||
AppLog.Warn($"알림 내용 복사 실패: {ex.Message}");
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
@@ -53,8 +53,7 @@ public partial class PreviewWindow : Window
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"인쇄 중 오류가 발생했습니다.\n\n{ex.Message}", "오류",
|
||||
MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
DialogService.Notify(DialogKind.Error, "오류", "인쇄 중 오류가 발생했습니다.", ex.Message, this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@ using System.Collections.ObjectModel;
|
||||
using System.Windows;
|
||||
using SheetMe.Data.Stores;
|
||||
|
||||
using SheetMe.Designer.Services;
|
||||
|
||||
namespace SheetMe.Designer.Views;
|
||||
|
||||
/// <summary>
|
||||
@@ -45,9 +47,9 @@ public partial class RecordWordDialogView : Window
|
||||
{
|
||||
return true;
|
||||
}
|
||||
MessageBox.Show("HIS 사용자가 확인되지 않아 상용구를 변경할 수 없습니다.\n" +
|
||||
"기록지정보 화면에서 서식생성기를 실행해 주세요.",
|
||||
"상용구 관리", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
DialogService.Notify(DialogKind.Warning, "상용구 관리",
|
||||
"HIS 사용자가 확인되지 않아 상용구를 변경할 수 없습니다.",
|
||||
"기록지정보 화면에서 서식생성기를 실행해 주세요.", this);
|
||||
return false;
|
||||
}
|
||||
#endregion
|
||||
@@ -65,8 +67,7 @@ public partial class RecordWordDialogView : Window
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"상용구 조회 중 오류가 발생했습니다.\n\n{ex.Message}", "오류",
|
||||
MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
DialogService.Notify(DialogKind.Error, "오류", "상용구 조회 중 오류가 발생했습니다.", ex.Message, this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,8 +88,7 @@ public partial class RecordWordDialogView : Window
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"추가 중 오류가 발생했습니다.\n\n{ex.Message}", "오류",
|
||||
MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
DialogService.Notify(DialogKind.Error, "오류", "추가 중 오류가 발생했습니다.", ex.Message, this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,8 +116,7 @@ public partial class RecordWordDialogView : Window
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"수정 중 오류가 발생했습니다.\n\n{ex.Message}", "오류",
|
||||
MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
DialogService.Notify(DialogKind.Error, "오류", "수정 중 오류가 발생했습니다.", ex.Message, this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,8 +126,8 @@ public partial class RecordWordDialogView : Window
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (MessageBox.Show($"삭제할까요?\n\n{Truncate(selected.Value)}", "상용구 삭제",
|
||||
MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes)
|
||||
if (!DialogService.Confirm("상용구 삭제", "삭제할까요?", Truncate(selected.Value),
|
||||
yes: "삭제", no: "취소", destructive: true, owner: this))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -139,8 +138,7 @@ public partial class RecordWordDialogView : Window
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"삭제 중 오류가 발생했습니다.\n\n{ex.Message}", "오류",
|
||||
MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
DialogService.Notify(DialogKind.Error, "오류", "삭제 중 오류가 발생했습니다.", ex.Message, this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,8 +162,7 @@ public partial class RecordWordDialogView : Window
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"순서 변경 중 오류가 발생했습니다.\n\n{ex.Message}", "오류",
|
||||
MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
DialogService.Notify(DialogKind.Error, "오류", "순서 변경 중 오류가 발생했습니다.", ex.Message, this);
|
||||
Reload();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Windows;
|
||||
using SheetMe.Designer.Services;
|
||||
|
||||
namespace SheetMe.Designer.Views;
|
||||
|
||||
@@ -30,7 +31,7 @@ public partial class RegisterSheetDialogView : Window
|
||||
{
|
||||
if (SheetCode.Length == 0 || SheetName.Length == 0)
|
||||
{
|
||||
MessageBox.Show("서식 코드와 명칭을 입력하세요.", "신규 서식 등록");
|
||||
DialogService.Notify(DialogKind.Warning, "신규 서식 등록", "서식 코드와 명칭을 입력하세요.", owner: this);
|
||||
return;
|
||||
}
|
||||
DialogResult = true;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System.Windows;
|
||||
using SheetMe.Data.Stores;
|
||||
|
||||
using SheetMe.Designer.Services;
|
||||
|
||||
namespace SheetMe.Designer.Views;
|
||||
|
||||
/// <summary>
|
||||
@@ -40,8 +42,7 @@ public partial class SheetOpenDialogView : Window
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"서식 목록 조회 중 오류가 발생했습니다.\n\n{ex.Message}", "오류",
|
||||
MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
DialogService.Notify(DialogKind.Error, "오류", "서식 목록 조회 중 오류가 발생했습니다.", ex.Message, this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,8 +54,7 @@ public partial class SheetOpenDialogView : Window
|
||||
}
|
||||
if (!selected.HasDesign)
|
||||
{
|
||||
MessageBox.Show("선택한 서식에는 저장된 디자인이 없습니다.", "열기",
|
||||
MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
DialogService.Notify(DialogKind.Warning, "열기", "선택한 서식에는 저장된 디자인이 없습니다.", owner: this);
|
||||
return;
|
||||
}
|
||||
SelectedSheet = selected;
|
||||
|
||||
Reference in New Issue
Block a user