169 lines
5.1 KiB
C#
169 lines
5.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
|
||
{
|
||
// ========== 对外接口 ==========
|
||
|
||
/// <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");
|
||
}
|
||
}
|
||
}
|