using System;
using System.ComponentModel;
using System.Linq;
using System.Windows;
namespace WxOrder.Framework.Commons.Dialogs
{
///
/// 静态弹窗服务:不依赖容器,直接传入 View 实例弹出。
/// ViewModel 需实现 IDialogAware。
///
public static class DialogService
{
// ========== 对外接口 ==========
public static bool ExistsWindow(FrameworkElement view)
{
var window = Application.Current.Windows.OfType().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().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 callback = null)
{
if (ExistsWindow(view))
{
ActivateWindow(view);
}
else
{
Show(view, parameters, callback);
}
}
/// 非模态弹出
public static void Show(FrameworkElement view,
IDialogParameters parameters = null,
Action callback = null,
IDialogWindow window = null)
{
ShowInternal(view, parameters, callback, false, window);
}
/// 模态弹出
public static void ShowDialog(FrameworkElement view,
IDialogParameters parameters = null,
Action callback = null,
IDialogWindow window = null)
{
ShowInternal(view, parameters, callback, true, window);
}
// ========== 内部实现 ==========
private static void ShowInternal(FrameworkElement view,
IDialogParameters parameters,
Action 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();
}
///
/// 把 View 挂到 DialogWindow 上,并触发 OnDialogOpened。
///
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);
}
///
/// 绑定 DialogWindow 的生命周期事件。
///
private static void ConfigureDialogWindowEvents(IDialogWindow dialogWindow, Action callback)
{
Action 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;
}
///
/// 设置 DialogWindow 的 Style / Content / DataContext / Owner。
///
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()
.FirstOrDefault(x => x.IsActive);
}
///
/// 从 window.Content 或 window.DataContext 里拿 IDialogAware。
/// 替代 Prism 的 dialogWindow.GetDialogViewModel() 扩展方法。
///
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");
}
}
}