增加MessageBoxService服务
This commit is contained in:
1 parent
3dcb6a1c34
commit
30a6a5ea24
15 files changed
+517
-153
No files matched your search
@@ -4,8 +4,8 @@
|
||||
xmlns:ext="clr-namespace:Store.Management.Framework.Controls"
|
||||
xmlns:f="clr-namespace:Store.Management.Framework.Controls.Attach;assembly=Store.Management.Framework"
|
||||
xmlns:local="clr-namespace:Store.Management.Framework.Controls"
|
||||
xmlns:wpf="MAX.WPF"
|
||||
xmlns:sys="clr-namespace:System;assembly=mscorlib">
|
||||
xmlns:sys="clr-namespace:System;assembly=mscorlib"
|
||||
xmlns:wpf="MAX.WPF">
|
||||
|
||||
|
||||
<sys:Double x:Key="DataGridExFontSize">12</sys:Double>
|
||||
@@ -498,6 +498,11 @@
|
||||
</Setter>
|
||||
</Style>
|
||||
</Style.Resources>
|
||||
<Setter Property="PageSizes">
|
||||
<Setter.Value>
|
||||
<Int32Collection>50,100,500,1000,2000</Int32Collection>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="UseLayoutRounding" Value="True" />
|
||||
<Setter Property="SnapsToDevicePixels" Value="True" />
|
||||
<Setter Property="Background" Value="White" />
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using MAX.Common.Helpers;
|
||||
using MAX.Framework.Logger;
|
||||
using NLog;
|
||||
using Prism.Autofac;
|
||||
@@ -15,141 +16,155 @@ namespace Store.Management.Framework;
|
||||
|
||||
public abstract class FrameworkApplication : PrismApplication
|
||||
{
|
||||
private Mutex? _mutex;
|
||||
private bool _ownsMutex;
|
||||
private int _fatalHandling;
|
||||
private int _shutdownRequested;
|
||||
public static bool ShuttingDown { get; private set; }
|
||||
public static bool IsAppInitialized { get; private set; }
|
||||
public static event Action<Exception>? FatalErrorRaised;
|
||||
private Mutex? _mutex;
|
||||
private bool _ownsMutex;
|
||||
private int _fatalHandling;
|
||||
private int _shutdownRequested;
|
||||
public static bool ShuttingDown { get; private set; }
|
||||
public static bool IsAppInitialized { get; private set; }
|
||||
public static event Action<Exception>? FatalErrorRaised;
|
||||
private IStatusBarService StatusBarService;
|
||||
private IMessageBoxService MessageBoxService;
|
||||
private static bool FatalShutdown = false;
|
||||
protected FrameworkApplication()
|
||||
{
|
||||
DispatcherUnhandledException += OnDispatcherUnhandledException;
|
||||
AppDomain.CurrentDomain.UnhandledException += OnDomainUnhandledException;
|
||||
TaskScheduler.UnobservedTaskException += OnUnobservedTaskException;
|
||||
}
|
||||
|
||||
protected FrameworkApplication()
|
||||
{
|
||||
DispatcherUnhandledException += OnDispatcherUnhandledException;
|
||||
AppDomain.CurrentDomain.UnhandledException += OnDomainUnhandledException;
|
||||
TaskScheduler.UnobservedTaskException += OnUnobservedTaskException;
|
||||
}
|
||||
/// <summary>返回 null 可允许多开;默认限制同一登录会话中的应用实例。</summary>
|
||||
public virtual string? GetMutexName() => @"Local\Store.Management";
|
||||
|
||||
/// <summary>返回 null 可允许多开;默认限制同一登录会话中的应用实例。</summary>
|
||||
public virtual string? GetMutexName() => @"Local\Store.Management";
|
||||
protected override void OnStartup(StartupEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
//string? name = GetMutexName();
|
||||
//if (!string.IsNullOrWhiteSpace(name))
|
||||
//{
|
||||
// _mutex = new Mutex(true, name, out _ownsMutex);
|
||||
// if (!_ownsMutex)
|
||||
// {
|
||||
// MessageBox.Show("程序已在运行。", Config.AppName, MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
// Shutdown();
|
||||
// return;
|
||||
// }
|
||||
//}
|
||||
FolderConfig.Initialize();
|
||||
base.OnStartup(e);
|
||||
ApplicationLogService.Initialize();
|
||||
NLogger.Instance.Info($"软件启动:{Config.AppFullName},版本:{Config.GetFullVersionString()},会话:{Config.SessionID},启动时间:{Config.AppStartTime:O},Windows:{Config.WindowsVersion}");
|
||||
DISource.Resolver = Resolve;
|
||||
}
|
||||
catch (Exception ex) { Fatal(ex); }
|
||||
}
|
||||
|
||||
protected override void OnStartup(StartupEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
//string? name = GetMutexName();
|
||||
//if (!string.IsNullOrWhiteSpace(name))
|
||||
//{
|
||||
// _mutex = new Mutex(true, name, out _ownsMutex);
|
||||
// if (!_ownsMutex)
|
||||
// {
|
||||
// MessageBox.Show("程序已在运行。", Config.AppName, MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
// Shutdown();
|
||||
// return;
|
||||
// }
|
||||
//}
|
||||
FolderConfig.Initialize();
|
||||
base.OnStartup(e);
|
||||
ApplicationLogService.Initialize();
|
||||
NLogger.Instance.Info($"软件启动:{Config.AppFullName},版本:{Config.GetFullVersionString()},会话:{Config.SessionID},启动时间:{Config.AppStartTime:O},Windows:{Config.WindowsVersion}");
|
||||
DISource.Resolver = Resolve;
|
||||
}
|
||||
catch (Exception ex) { Fatal(ex); }
|
||||
}
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
IsAppInitialized = true;
|
||||
NLogger.Instance.Info("软件初始化成功,进入主页面");
|
||||
StatusBarService = Container?.Resolve<IStatusBarService>();
|
||||
MessageBoxService = Container?.Resolve<IMessageBoxService>();
|
||||
}
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
IsAppInitialized = true;
|
||||
NLogger.Instance.Info("软件初始化成功,进入主页面");
|
||||
}
|
||||
protected override void RegisterRequiredTypes(IContainerRegistry registry)
|
||||
{
|
||||
base.RegisterRequiredTypes(registry);
|
||||
registry.RegisterDialogWindow<Controls.DialogWindow>();
|
||||
}
|
||||
|
||||
protected override void RegisterRequiredTypes(IContainerRegistry registry)
|
||||
{
|
||||
base.RegisterRequiredTypes(registry);
|
||||
registry.RegisterDialogWindow<Controls.DialogWindow>();
|
||||
}
|
||||
private object Resolve(Type type, string name)
|
||||
{
|
||||
if (type == null || Container is null) return null!;
|
||||
return name != null ? Container.Resolve(type, name) : Container.Resolve(type);
|
||||
}
|
||||
|
||||
private object Resolve(Type type, string name)
|
||||
{
|
||||
if (type == null || Container is null) return null!;
|
||||
return name != null ? Container.Resolve(type, name) : Container.Resolve(type);
|
||||
}
|
||||
private void OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
|
||||
{
|
||||
e.Handled = true;
|
||||
StatusBarService.Report(e.Exception.Message, StatusLevel.Error);
|
||||
Fatal(e.Exception);
|
||||
|
||||
private void OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
|
||||
{
|
||||
e.Handled = true;
|
||||
Fatal(e.Exception);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDomainUnhandledException(object sender, UnhandledExceptionEventArgs e)
|
||||
{
|
||||
Exception exception = e.ExceptionObject as Exception ?? new Exception(e.ExceptionObject?.ToString());
|
||||
// CLR 终止期间同步记录,不等待 UI 线程。
|
||||
if (e.IsTerminating) ApplicationLogService.WriteFatal(exception, "AppDomain.UnhandledException");
|
||||
else Fatal(exception);
|
||||
}
|
||||
private void OnDomainUnhandledException(object sender, UnhandledExceptionEventArgs e)
|
||||
{
|
||||
Exception exception = e.ExceptionObject as Exception ?? new Exception(e.ExceptionObject?.ToString());
|
||||
StatusBarService.Report(exception.Message, StatusLevel.Error);
|
||||
// CLR 终止期间同步记录,不等待 UI 线程。
|
||||
if (e.IsTerminating) ApplicationLogService.WriteFatal(exception, "AppDomain.UnhandledException");
|
||||
else Fatal(exception);
|
||||
}
|
||||
|
||||
private void OnUnobservedTaskException(object? sender, UnobservedTaskExceptionEventArgs e)
|
||||
{
|
||||
ApplicationLogService.WriteFatal(e.Exception, "TaskScheduler.UnobservedTaskException");
|
||||
e.SetObserved();
|
||||
}
|
||||
private void OnUnobservedTaskException(object? sender, UnobservedTaskExceptionEventArgs e)
|
||||
{
|
||||
ApplicationLogService.WriteFatal(e.Exception, "TaskScheduler.UnobservedTaskException");
|
||||
e.SetObserved();
|
||||
}
|
||||
|
||||
/// <summary>先同步保存报告,再通知订阅者并关闭应用。</summary>
|
||||
public static void Fatal(Exception exception)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(exception);
|
||||
string? path = ApplicationLogService.WriteFatal(exception, "Fatal");
|
||||
if (Current is not FrameworkApplication app || Interlocked.Exchange(ref app._fatalHandling, 1) != 0) return;
|
||||
foreach (Action<Exception> handler in FatalErrorRaised?.GetInvocationList() ?? [])
|
||||
{
|
||||
try { handler(exception); }
|
||||
catch (Exception ex) { ApplicationLogService.WriteFatal(ex, "FatalErrorRaised"); }
|
||||
}
|
||||
void ShowErrorAndShutdown()
|
||||
{
|
||||
try
|
||||
{
|
||||
MessageBox.Show($"软件发生致命错误,即将关闭。\n{exception.Message}\n\n日志:{path ?? "写入失败,请查看调试输出"}",
|
||||
Config.AppName, MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
finally { TotalShutdown(-1); }
|
||||
}
|
||||
if (app.Dispatcher.CheckAccess()) ShowErrorAndShutdown();
|
||||
else if (!app.Dispatcher.HasShutdownStarted) app.Dispatcher.BeginInvoke((Action)ShowErrorAndShutdown);
|
||||
}
|
||||
/// <summary>先同步保存报告,再通知订阅者并关闭应用。</summary>
|
||||
public void Fatal(Exception exception)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(exception);
|
||||
string? path = ApplicationLogService.WriteFatal(exception, "Fatal");
|
||||
if (Current is not FrameworkApplication app || Interlocked.Exchange(ref app._fatalHandling, 1) != 0) return;
|
||||
foreach (Action<Exception> handler in FatalErrorRaised?.GetInvocationList() ?? [])
|
||||
{
|
||||
try { handler(exception); }
|
||||
catch (Exception ex) { ApplicationLogService.WriteFatal(ex, "FatalErrorRaised"); }
|
||||
}
|
||||
void ShowErrorAndShutdown()
|
||||
{
|
||||
if (FatalShutdown)
|
||||
{
|
||||
try
|
||||
{
|
||||
MessageBox.Show($"软件发生致命错误,即将关闭。\n{exception.Message}\n\n日志:{path ?? "写入失败,请查看调试输出"}",
|
||||
Config.AppName, MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
finally { TotalShutdown(-1); }
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBoxService.ShowError(exception.Message);
|
||||
}
|
||||
}
|
||||
if (app.Dispatcher.CheckAccess()) ShowErrorAndShutdown();
|
||||
else if (!app.Dispatcher.HasShutdownStarted) app.Dispatcher.BeginInvoke((Action)ShowErrorAndShutdown);
|
||||
}
|
||||
|
||||
/// <summary>通过 WPF 正常退出,执行退出清理。</summary>
|
||||
public static void TotalShutdown(int exitCode = 0)
|
||||
{
|
||||
if (Current is not FrameworkApplication app || Interlocked.Exchange(ref app._shutdownRequested, 1) != 0) return;
|
||||
ShuttingDown = true;
|
||||
if (app.Dispatcher.CheckAccess()) app.Shutdown(exitCode);
|
||||
else if (!app.Dispatcher.HasShutdownStarted) app.Dispatcher.BeginInvoke((Action)(() => app.Shutdown(exitCode)));
|
||||
}
|
||||
/// <summary>通过 WPF 正常退出,执行退出清理。</summary>
|
||||
public static void TotalShutdown(int exitCode = 0)
|
||||
{
|
||||
if (Current is not FrameworkApplication app || Interlocked.Exchange(ref app._shutdownRequested, 1) != 0) return;
|
||||
ShuttingDown = true;
|
||||
if (app.Dispatcher.CheckAccess()) app.Shutdown(exitCode);
|
||||
else if (!app.Dispatcher.HasShutdownStarted) app.Dispatcher.BeginInvoke((Action)(() => app.Shutdown(exitCode)));
|
||||
}
|
||||
|
||||
protected override void OnExit(ExitEventArgs e)
|
||||
{
|
||||
ShuttingDown = true;
|
||||
try
|
||||
{
|
||||
try { Container?.Resolve<StoreApiClient>().Dispose(); }
|
||||
finally { base.OnExit(e); }
|
||||
}
|
||||
finally
|
||||
{
|
||||
DispatcherUnhandledException -= OnDispatcherUnhandledException;
|
||||
AppDomain.CurrentDomain.UnhandledException -= OnDomainUnhandledException;
|
||||
TaskScheduler.UnobservedTaskException -= OnUnobservedTaskException;
|
||||
DISource.Resolver = null!;
|
||||
try { if (_ownsMutex) _mutex?.ReleaseMutex(); }
|
||||
finally
|
||||
{
|
||||
_mutex?.Dispose();
|
||||
try { NLogger.Instance.Info($"软件关闭,退出码:{e.ApplicationExitCode}"); }
|
||||
finally { LogManager.Shutdown(); }
|
||||
}
|
||||
}
|
||||
}
|
||||
protected override void OnExit(ExitEventArgs e)
|
||||
{
|
||||
ShuttingDown = true;
|
||||
try
|
||||
{
|
||||
try { Container?.Resolve<StoreApiClient>().Dispose(); }
|
||||
finally { base.OnExit(e); }
|
||||
}
|
||||
finally
|
||||
{
|
||||
DispatcherUnhandledException -= OnDispatcherUnhandledException;
|
||||
AppDomain.CurrentDomain.UnhandledException -= OnDomainUnhandledException;
|
||||
TaskScheduler.UnobservedTaskException -= OnUnobservedTaskException;
|
||||
DISource.Resolver = null!;
|
||||
try { if (_ownsMutex) _mutex?.ReleaseMutex(); }
|
||||
finally
|
||||
{
|
||||
_mutex?.Dispose();
|
||||
try { NLogger.Instance.Info($"软件关闭,退出码:{e.ApplicationExitCode}"); }
|
||||
finally { LogManager.Shutdown(); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Store.Management.Framework.Interfaces
|
||||
{
|
||||
|
||||
public interface IMessageBoxService
|
||||
{
|
||||
|
||||
//MessageResult Show(string messageBoxText, string caption, MessageBoxButton button, MessageIcon icon, MessageResult defaultResult);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using MAX.Core.Commons;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Store.Management.Framework
|
||||
{
|
||||
public interface IMessageBoxService
|
||||
{
|
||||
MessageResult Show(string messageBoxText, string caption, MessageButton button, MessageIcon icon, MessageResult defaultResult);
|
||||
|
||||
|
||||
void ShowInformation(string content);
|
||||
void ShowWarning(string content);
|
||||
void ShowError(string content);
|
||||
void ShowError(string content, Exception exception);
|
||||
bool ShowYesNoQuestion(string content);
|
||||
bool ShowYesNoWarning(string content);
|
||||
bool ShowYesNoError(string content);
|
||||
bool ShowOkCancelQuestion(string content);
|
||||
bool ShowOkCancelWarning(string content);
|
||||
bool ShowOkCancelError(string content);
|
||||
MessageResult ShowYesNoCancelQuestion(string content);
|
||||
MessageResult ShowYesNoCancelWarning(string content);
|
||||
MessageResult ShowYesNoCancelError(string content);
|
||||
}
|
||||
}
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
|
||||
namespace Store.Management.Framework
|
||||
{
|
||||
public static class MessageBoxEnumsConverter
|
||||
{
|
||||
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static bool? ToBool(this MessageBoxResult result)
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
case MessageBoxResult.Cancel: return null;
|
||||
case MessageBoxResult.No: return false;
|
||||
default: return true;
|
||||
}
|
||||
}
|
||||
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static bool? ToBool(this MessageResult result)
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
case MessageResult.Cancel: return null;
|
||||
case MessageResult.No: return false;
|
||||
default: return true;
|
||||
}
|
||||
}
|
||||
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static MessageBoxResult ToMessageBoxResult(this MessageResult result)
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
case MessageResult.Cancel: return MessageBoxResult.Cancel;
|
||||
case MessageResult.No: return MessageBoxResult.No;
|
||||
case MessageResult.Yes: return MessageBoxResult.Yes;
|
||||
case MessageResult.OK: return MessageBoxResult.OK;
|
||||
default: return MessageBoxResult.None;
|
||||
}
|
||||
}
|
||||
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static MessageResult ToMessageResult(this MessageBoxResult result)
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
case MessageBoxResult.Cancel: return MessageResult.Cancel;
|
||||
case MessageBoxResult.No: return MessageResult.No;
|
||||
case MessageBoxResult.Yes: return MessageResult.Yes;
|
||||
case MessageBoxResult.OK: return MessageResult.OK;
|
||||
default: return MessageResult.None;
|
||||
}
|
||||
}
|
||||
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static MessageBoxButton ToMessageBoxButton(this MessageButton button)
|
||||
{
|
||||
switch (button)
|
||||
{
|
||||
case MessageButton.OKCancel: return MessageBoxButton.OKCancel;
|
||||
case MessageButton.YesNo: return MessageBoxButton.YesNo;
|
||||
case MessageButton.YesNoCancel: return MessageBoxButton.YesNoCancel;
|
||||
default: return MessageBoxButton.OK;
|
||||
}
|
||||
}
|
||||
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static MessageButton ToMessageButton(this MessageBoxButton button)
|
||||
{
|
||||
switch (button)
|
||||
{
|
||||
case MessageBoxButton.OKCancel: return MessageButton.OKCancel;
|
||||
case MessageBoxButton.YesNo: return MessageButton.YesNo;
|
||||
case MessageBoxButton.YesNoCancel: return MessageButton.YesNoCancel;
|
||||
default: return MessageButton.OK;
|
||||
}
|
||||
}
|
||||
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static MessageBoxImage ToMessageBoxImage(this MessageIcon icon)
|
||||
{
|
||||
switch (icon)
|
||||
{
|
||||
case MessageIcon.Error: return MessageBoxImage.Error;
|
||||
case MessageIcon.Information: return MessageBoxImage.Information;
|
||||
case MessageIcon.Question: return MessageBoxImage.Question;
|
||||
case MessageIcon.Warning: return MessageBoxImage.Warning;
|
||||
default: return MessageBoxImage.None;
|
||||
}
|
||||
}
|
||||
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static MessageIcon ToMessageIcon(this MessageBoxImage icon)
|
||||
{
|
||||
switch (icon)
|
||||
{
|
||||
case MessageBoxImage.Error: return MessageIcon.Error;
|
||||
case MessageBoxImage.Information: return MessageIcon.Information;
|
||||
case MessageBoxImage.Question: return MessageIcon.Question;
|
||||
case MessageBoxImage.Warning: return MessageIcon.Warning;
|
||||
default: return MessageIcon.None;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
using MAX.Core.DependencyInjection;
|
||||
using Store.Management.Framework.Configs;
|
||||
using System.Windows;
|
||||
using MessageBox = HandyControl.Controls.MessageBox;
|
||||
|
||||
namespace Store.Management.Framework
|
||||
{
|
||||
public class MessageBoxService : IMessageBoxService, ISingletonDependency
|
||||
{
|
||||
protected readonly Guid id = Guid.NewGuid();
|
||||
|
||||
public string MessageTitle { get; set; } = string.Empty;
|
||||
|
||||
public MessageBoxService()
|
||||
{
|
||||
MessageTitle = AppConfig.AppDisplayName;
|
||||
}
|
||||
|
||||
public virtual MessageResult Show(string messageBoxText, string caption, MessageButton button, MessageIcon icon, MessageResult defaultResult)
|
||||
{
|
||||
Window? window = Application.Current?.Windows.OfType<Window>().FirstOrDefault(w => w.IsActive);
|
||||
if (window is null)
|
||||
{
|
||||
return MessageBox.Show(
|
||||
messageBoxText: messageBoxText,
|
||||
caption: caption,
|
||||
button: button.ToMessageBoxButton(),
|
||||
icon: icon.ToMessageBoxImage(),
|
||||
defaultResult: defaultResult.ToMessageBoxResult()
|
||||
).ToMessageResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
return MessageBox.Show(
|
||||
owner: window,
|
||||
messageBoxText: messageBoxText,
|
||||
caption: caption,
|
||||
button: button.ToMessageBoxButton(),
|
||||
icon: icon.ToMessageBoxImage(),
|
||||
defaultResult: defaultResult.ToMessageBoxResult()
|
||||
).ToMessageResult();
|
||||
}
|
||||
}
|
||||
|
||||
public void ShowInformation(string content)
|
||||
{
|
||||
this.ShowMessage(content, MessageTitle, MessageButton.OK, MessageIcon.Information, MessageResult.OK);
|
||||
}
|
||||
|
||||
public void ShowWarning(string content)
|
||||
{
|
||||
this.ShowMessage(content, MessageTitle, MessageButton.OK, MessageIcon.Warning, MessageResult.OK);
|
||||
}
|
||||
|
||||
public void ShowError(string content, Exception exception)
|
||||
{
|
||||
if (exception is null)
|
||||
{
|
||||
ShowError(content);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.ShowMessage(content + "\n" + exception.Message, MessageTitle, MessageButton.OK, MessageIcon.Error, MessageResult.OK);
|
||||
}
|
||||
}
|
||||
|
||||
public void ShowError(string content)
|
||||
{
|
||||
this.ShowMessage(content, MessageTitle, MessageButton.OK, MessageIcon.Error, MessageResult.OK);
|
||||
}
|
||||
|
||||
public bool ShowYesNoQuestion(string content)
|
||||
{
|
||||
MessageResult result = this.ShowMessage(content, MessageTitle, MessageButton.YesNo, MessageIcon.Question, MessageResult.No);
|
||||
return result == MessageResult.Yes;
|
||||
}
|
||||
|
||||
public bool ShowYesNoWarning(string content)
|
||||
{
|
||||
MessageResult result = this.ShowMessage(content, MessageTitle, MessageButton.YesNo, MessageIcon.Warning, MessageResult.No);
|
||||
return result == MessageResult.Yes;
|
||||
}
|
||||
|
||||
public bool ShowYesNoError(string content)
|
||||
{
|
||||
MessageResult result = this.ShowMessage(content, MessageTitle, MessageButton.YesNo, MessageIcon.Error, MessageResult.No);
|
||||
return result == MessageResult.Yes;
|
||||
}
|
||||
|
||||
public bool ShowOkCancelQuestion(string content)
|
||||
{
|
||||
MessageResult result = this.ShowMessage(content, MessageTitle, MessageButton.OKCancel, MessageIcon.Question, MessageResult.OK);
|
||||
return result == MessageResult.OK;
|
||||
}
|
||||
|
||||
public bool ShowOkCancelWarning(string content)
|
||||
{
|
||||
MessageResult result = this.ShowMessage(content, MessageTitle, MessageButton.OKCancel, MessageIcon.Warning, MessageResult.OK);
|
||||
return result == MessageResult.OK;
|
||||
}
|
||||
|
||||
public bool ShowOkCancelError(string content)
|
||||
{
|
||||
MessageResult result = this.ShowMessage(content, MessageTitle, MessageButton.OKCancel, MessageIcon.Error, MessageResult.OK);
|
||||
return result == MessageResult.OK;
|
||||
}
|
||||
|
||||
public MessageResult ShowYesNoCancelQuestion(string content)
|
||||
{
|
||||
return this.ShowMessage(content, MessageTitle, MessageButton.YesNoCancel, MessageIcon.Question, MessageResult.Cancel);
|
||||
}
|
||||
|
||||
public MessageResult ShowYesNoCancelWarning(string content)
|
||||
{
|
||||
return this.ShowMessage(content, MessageTitle, MessageButton.YesNoCancel, MessageIcon.Warning, MessageResult.Cancel);
|
||||
}
|
||||
|
||||
public MessageResult ShowYesNoCancelError(string content)
|
||||
{
|
||||
return this.ShowMessage(content, MessageTitle, MessageButton.YesNoCancel, MessageIcon.Error, MessageResult.Cancel);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
namespace Store.Management.Framework
|
||||
{
|
||||
public static class MessageBoxServiceExtensions
|
||||
{
|
||||
extension(IMessageBoxService service)
|
||||
{
|
||||
public MessageResult ShowMessage(string messageBoxText, string caption, MessageButton button, MessageIcon icon, MessageResult defaultResult)
|
||||
{
|
||||
VerifyService(service);
|
||||
return service.Show(messageBoxText, caption, button, icon, defaultResult);
|
||||
}
|
||||
public bool? ShowMessage(string messageBoxText)
|
||||
{
|
||||
return service.ShowMessage(messageBoxText, string.Empty);
|
||||
}
|
||||
public bool? ShowMessage(string messageBoxText, string caption)
|
||||
{
|
||||
return service.ShowMessage(messageBoxText, caption, MessageButton.OK).ToBool();
|
||||
}
|
||||
public MessageResult ShowMessage(string messageBoxText, string caption, MessageButton button)
|
||||
{
|
||||
return service.ShowMessage(messageBoxText, caption, button, MessageIcon.None);
|
||||
}
|
||||
public MessageResult ShowMessage(string messageBoxText, string caption, MessageButton button, MessageIcon icon)
|
||||
{
|
||||
VerifyService(service);
|
||||
return service.Show(messageBoxText, caption, button, icon, MessageResult.None);
|
||||
}
|
||||
}
|
||||
|
||||
static void VerifyService(IMessageBoxService service)
|
||||
{
|
||||
if (service == null)
|
||||
throw new ArgumentNullException(nameof(service));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Store.Management.Framework
|
||||
{
|
||||
public enum MessageButton
|
||||
{
|
||||
OK, OKCancel, YesNoCancel, YesNo,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Store.Management.Framework
|
||||
{
|
||||
public enum MessageIcon
|
||||
{
|
||||
None, Error, Question, Warning, Information,
|
||||
Hand = Error, Stop = Error, Exclamation = Warning, Asterisk = Information
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Store.Management.Framework
|
||||
{
|
||||
public enum MessageResult
|
||||
{
|
||||
None, OK, Cancel, Yes, No,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using MAX.Core.DependencyInjection;
|
||||
using Store.Management.Api;
|
||||
using Store.Management.Api.Models;
|
||||
using Store.Management.Api.Users;
|
||||
|
||||
namespace Store.Management.Framework.Services;
|
||||
|
||||
public interface IUserService
|
||||
{
|
||||
Task<PageResult<UserInfo>> SearchAsync(UserSearchRequest request, CancellationToken cancellationToken = default);
|
||||
Task<UserInfo> CreateAsync(UserCreateRequest request, CancellationToken cancellationToken = default);
|
||||
Task<UserInfo> UpdateAsync(UserUpdateRequest request, CancellationToken cancellationToken = default);
|
||||
Task DeleteAsync(int id, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
internal sealed class UserService(StoreApiClient client) : IUserService, ISingletonDependency
|
||||
{
|
||||
public Task<PageResult<UserInfo>> SearchAsync(UserSearchRequest request, CancellationToken cancellationToken = default)
|
||||
=> client.Users.SearchAsync(request, cancellationToken);
|
||||
|
||||
public Task<UserInfo> CreateAsync(UserCreateRequest request, CancellationToken cancellationToken = default)
|
||||
=> client.Users.CreateAsync(request, cancellationToken);
|
||||
|
||||
public Task<UserInfo> UpdateAsync(UserUpdateRequest request, CancellationToken cancellationToken = default)
|
||||
=> client.Users.UpdateAsync(request, cancellationToken);
|
||||
|
||||
public Task DeleteAsync(int id, CancellationToken cancellationToken = default)
|
||||
=> client.Users.DeleteAsync(id, cancellationToken);
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
using Prism.Commands;
|
||||
using Prism.Services.Dialogs;
|
||||
using Store.Management.Api;
|
||||
using Store.Management.Api.Transport;
|
||||
using Store.Management.Api.Users;
|
||||
using Store.Management.Framework.Controls;
|
||||
using Store.Management.Framework.Services;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace Store.Management.ViewModels;
|
||||
|
||||
public sealed class UserEditorDialogViewModel(StoreApiClient client) : ConfirmDialogViewModel
|
||||
public sealed class UserEditorDialogViewModel(IUserService userService) : ConfirmDialogViewModel
|
||||
{
|
||||
public const int UserNameLimit = 20;
|
||||
public const int PasswordLimit = 128;
|
||||
@@ -65,11 +65,11 @@ public sealed class UserEditorDialogViewModel(StoreApiClient client) : ConfirmDi
|
||||
{
|
||||
if (Draft is UserCreateRequest newUser)
|
||||
{
|
||||
await client.Users.CreateAsync(newUser);
|
||||
await userService.CreateAsync(newUser);
|
||||
}
|
||||
else
|
||||
{
|
||||
await client.Users.UpdateAsync((UserUpdateRequest)Draft);
|
||||
await userService.UpdateAsync((UserUpdateRequest)Draft);
|
||||
}
|
||||
}
|
||||
catch (ApiException ex)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using Prism.Commands;
|
||||
using Prism.Mvvm;
|
||||
using Prism.Services.Dialogs;
|
||||
using Store.Management.Api;
|
||||
using Store.Management.Api.Models;
|
||||
using Store.Management.Api.Transport;
|
||||
using Store.Management.Api.Users;
|
||||
@@ -13,7 +12,7 @@ using System.Windows.Controls.Primitives;
|
||||
|
||||
namespace Store.Management.ViewModels;
|
||||
|
||||
public sealed class UserManagementPageViewModel(StoreApiClient client, IDialogService dialogs, IStatusBarService statusBar) : BindableBase
|
||||
public sealed class UserManagementPageViewModel(IUserService userService, IDialogService dialogs, IStatusBarService statusBar) : BindableBase
|
||||
{
|
||||
public const int KeywordLimit = 100;
|
||||
private string appliedKeyword = "";
|
||||
@@ -59,13 +58,13 @@ public sealed class UserManagementPageViewModel(StoreApiClient client, IDialogSe
|
||||
{
|
||||
statusBar.Report("正在查询用户…");
|
||||
UserSearchRequest request = new() { Keyword = keyword, Page = page, PageSize = size };
|
||||
PageResult<UserInfo> result = await client.Users.SearchAsync(request);
|
||||
PageResult<UserInfo> result = await userService.SearchAsync(request);
|
||||
// 删除末页最后一条记录后,按服务端总数回到有效页。
|
||||
int lastPage = (int)Math.Clamp((result.Total - 1) / size + 1, 1, page);
|
||||
if (page > lastPage)
|
||||
{
|
||||
request.Page = lastPage;
|
||||
result = await client.Users.SearchAsync(request);
|
||||
result = await userService.SearchAsync(request);
|
||||
}
|
||||
appliedKeyword = keyword;
|
||||
pageSize = size;
|
||||
@@ -86,6 +85,7 @@ public sealed class UserManagementPageViewModel(StoreApiClient client, IDialogSe
|
||||
pageSize = size;
|
||||
statusBar.Report(ex.Message, StatusLevel.Error);
|
||||
}
|
||||
|
||||
finally
|
||||
{
|
||||
CanInteract = true;
|
||||
@@ -115,7 +115,7 @@ public sealed class UserManagementPageViewModel(StoreApiClient client, IDialogSe
|
||||
try
|
||||
{
|
||||
statusBar.Report("正在删除用户…");
|
||||
await client.Users.DeleteAsync(user.Id);
|
||||
await userService.DeleteAsync(user.Id);
|
||||
}
|
||||
catch (ApiException ex)
|
||||
{
|
||||
|
||||
@@ -127,6 +127,9 @@
|
||||
ShowRowNumber="True"
|
||||
ShowToolbar="True"
|
||||
TotalItemCount="{Binding TotalCount, Mode=OneWay}">
|
||||
<!--<f:DataGridEx.PageSizes>
|
||||
<Int32Collection>50,100,500,1000</Int32Collection>
|
||||
</f:DataGridEx.PageSizes>-->
|
||||
<f:DataGridEx.ToolbarContent>
|
||||
<ItemsControl>
|
||||
<ItemsControl.ItemsPanel>
|
||||
|
||||
Reference in new issue
Block a user