203 lines
6.1 KiB
C#
203 lines
6.1 KiB
C#
using System;
|
||
using System.ComponentModel;
|
||
using System.Linq;
|
||
using System.Windows;
|
||
|
||
namespace WxOrder.Framework.Commons.Dialogs
|
||
{
|
||
/// <summary>
|
||
/// 静态弹窗服务:不依赖容器,直接传入 View 实例弹出。
|
||
/// ViewModel 需实现 IDialogAware。
|
||
/// </summary>
|
||
public static class DialogService
|
||
{
|
||
// ========== 对外接口 ==========
|
||
public static bool ExistsWindow(FrameworkElement view)
|
||
{
|
||
var window = Application.Current.Windows.OfType<Window>().FirstOrDefault(w => w.Content != null && w.Content.GetType() == view.GetType());
|
||
return window != null;
|
||
}
|
||
public static void ActivateWindow(FrameworkElement view)
|
||
{
|
||
var window = Application.Current.Windows.OfType<Window>().FirstOrDefault(w => w.Content != null && w.Content.GetType() == view.GetType());
|
||
if (window == null)
|
||
return;
|
||
|
||
if (!window.IsVisible)
|
||
window.Show();
|
||
if (window.WindowState == WindowState.Minimized)
|
||
window.WindowState = WindowState.Normal;
|
||
|
||
if (!window.Activate())
|
||
{
|
||
// 窗口被其他进程遮挡时,短暂置顶以切换到用户面前。
|
||
window.Topmost = true;
|
||
window.Topmost = false;
|
||
window.Activate();
|
||
}
|
||
}
|
||
public static void ShowOrActivateWindow(FrameworkElement view, IDialogParameters parameters = null, Action<IDialogResult> callback = null)
|
||
{
|
||
if (ExistsWindow(view))
|
||
{
|
||
ActivateWindow(view);
|
||
}
|
||
else
|
||
{
|
||
Show(view, parameters, callback);
|
||
}
|
||
}
|
||
/// <summary>非模态弹出</summary>
|
||
public static void Show(FrameworkElement view,
|
||
IDialogParameters parameters = null,
|
||
Action<IDialogResult> callback = null,
|
||
IDialogWindow window = null)
|
||
{
|
||
ShowInternal(view, parameters, callback, false, window);
|
||
}
|
||
|
||
/// <summary>模态弹出</summary>
|
||
public static void ShowDialog(FrameworkElement view,
|
||
IDialogParameters parameters = null,
|
||
Action<IDialogResult> callback = null,
|
||
IDialogWindow window = null)
|
||
{
|
||
ShowInternal(view, parameters, callback, true, window);
|
||
}
|
||
|
||
// ========== 内部实现 ==========
|
||
|
||
private static void ShowInternal(FrameworkElement view,
|
||
IDialogParameters parameters,
|
||
Action<IDialogResult> callback,
|
||
bool isModal,
|
||
IDialogWindow window)
|
||
{
|
||
if (view == null) throw new ArgumentNullException(nameof(view));
|
||
if (parameters == null) parameters = new DialogParameters();
|
||
|
||
// 1. 创建(或使用传入的)DialogWindow
|
||
var dialogWindow = window ?? new DialogWindow();
|
||
|
||
// 2. 绑定事件(关闭、回调等)
|
||
ConfigureDialogWindowEvents(dialogWindow, callback);
|
||
|
||
// 3. 配置内容(View + ViewModel)
|
||
ConfigureDialogWindowContent(view, dialogWindow, parameters);
|
||
|
||
// 4. 弹出
|
||
ShowDialogWindow(dialogWindow, isModal);
|
||
}
|
||
|
||
private static void ShowDialogWindow(IDialogWindow dialogWindow, bool isModal)
|
||
{
|
||
if (isModal)
|
||
dialogWindow.ShowDialog();
|
||
else
|
||
dialogWindow.Show();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 把 View 挂到 DialogWindow 上,并触发 OnDialogOpened。
|
||
/// </summary>
|
||
private static void ConfigureDialogWindowContent(FrameworkElement dialogContent,
|
||
IDialogWindow window,
|
||
IDialogParameters parameters)
|
||
{
|
||
// 不再自动绑 ViewModel,DataContext 由 View 自己负责
|
||
if (!(dialogContent.DataContext is IDialogAware viewModel))
|
||
throw new NullReferenceException("A dialog's ViewModel must implement the IDialogAware interface");
|
||
|
||
ConfigureDialogWindowProperties(window, dialogContent, viewModel);
|
||
|
||
// 直接触发 OnDialogOpened(替代 MvvmHelpers.ViewAndViewModelAction)
|
||
viewModel.OnDialogOpened(parameters);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 绑定 DialogWindow 的生命周期事件。
|
||
/// </summary>
|
||
private static void ConfigureDialogWindowEvents(IDialogWindow dialogWindow, Action<IDialogResult> callback)
|
||
{
|
||
Action<IDialogResult> requestCloseHandler = null;
|
||
requestCloseHandler = (o) =>
|
||
{
|
||
dialogWindow.Result = o;
|
||
dialogWindow.Close();
|
||
};
|
||
|
||
RoutedEventHandler loadedHandler = null;
|
||
loadedHandler = (o, e) =>
|
||
{
|
||
dialogWindow.Loaded -= loadedHandler;
|
||
GetDialogViewModel(dialogWindow).RequestClose += requestCloseHandler;
|
||
};
|
||
dialogWindow.Loaded += loadedHandler;
|
||
|
||
CancelEventHandler closingHandler = null;
|
||
closingHandler = (o, e) =>
|
||
{
|
||
if (!GetDialogViewModel(dialogWindow).CanCloseDialog())
|
||
e.Cancel = true;
|
||
};
|
||
dialogWindow.Closing += closingHandler;
|
||
|
||
EventHandler closedHandler = null;
|
||
closedHandler = (o, e) =>
|
||
{
|
||
dialogWindow.Closed -= closedHandler;
|
||
dialogWindow.Closing -= closingHandler;
|
||
GetDialogViewModel(dialogWindow).RequestClose -= requestCloseHandler;
|
||
GetDialogViewModel(dialogWindow).OnDialogClosed();
|
||
|
||
|
||
if (dialogWindow.Result == null)
|
||
dialogWindow.Result = new DialogResult();
|
||
|
||
callback?.Invoke(dialogWindow.Result);
|
||
|
||
dialogWindow.DataContext = null;
|
||
dialogWindow.Content = null;
|
||
};
|
||
dialogWindow.Closed += closedHandler;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置 DialogWindow 的 Style / Content / DataContext / Owner。
|
||
/// </summary>
|
||
private static void ConfigureDialogWindowProperties(IDialogWindow window,
|
||
FrameworkElement dialogContent,
|
||
IDialogAware viewModel)
|
||
{
|
||
var windowStyle = Dialog.GetWindowStyle(dialogContent);
|
||
if (windowStyle != null)
|
||
window.Style = windowStyle;
|
||
|
||
window.Content = dialogContent;
|
||
window.DataContext = viewModel; // 宿主窗口和对话框共享同一个 DataContext
|
||
|
||
if (window.Owner == null)
|
||
window.Owner = Application.Current?.Windows
|
||
.OfType<Window>()
|
||
.FirstOrDefault(x => x.IsActive);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 从 window.Content 或 window.DataContext 里拿 IDialogAware。
|
||
/// 替代 Prism 的 dialogWindow.GetDialogViewModel() 扩展方法。
|
||
/// </summary>
|
||
private static IDialogAware GetDialogViewModel(IDialogWindow window)
|
||
{
|
||
if (window.Content is FrameworkElement fe)
|
||
{
|
||
if (fe is IDialogAware aware) return aware;
|
||
if (fe.DataContext is IDialogAware vm) return vm;
|
||
}
|
||
|
||
if (window.DataContext is IDialogAware wvm) return wvm;
|
||
|
||
throw new NullReferenceException("A dialog's ViewModel must implement the IDialogAware interface");
|
||
}
|
||
}
|
||
}
|