Files
29WxOrder/WxOrder.Framework/Commons/Dialogs/DialogService.cs
T

203 lines
6.1 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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");
}
}
}