105 lines
3.8 KiB
C#
105 lines
3.8 KiB
C#
|
|
using MainShell.Resources.CustomControl;
|
|||
|
|
using System;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
using System.Linq;
|
|||
|
|
using System.Text;
|
|||
|
|
using System.Threading;
|
|||
|
|
using System.Threading.Tasks;
|
|||
|
|
using System.Windows;
|
|||
|
|
using System.Windows.Controls;
|
|||
|
|
|
|||
|
|
namespace MainShell.Common
|
|||
|
|
{
|
|||
|
|
public static class Loading
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
private static LoadingWaitView _view;
|
|||
|
|
|
|||
|
|
// 全局初始化:在主程序启动或插件加载时调用一次
|
|||
|
|
public static void Initialize(Window mainWindow)
|
|||
|
|
{
|
|||
|
|
if (_view != null) return; // 避免重复加载
|
|||
|
|
|
|||
|
|
_view = new LoadingWaitView();
|
|||
|
|
|
|||
|
|
// 获取窗口的根内容
|
|||
|
|
var rootContent = mainWindow.Content;
|
|||
|
|
|
|||
|
|
if (rootContent is Panel rootPanel)
|
|||
|
|
{
|
|||
|
|
// 如果根部本来就是 Panel (Grid/Canvas等),直接添加
|
|||
|
|
rootPanel.Children.Add(_view);
|
|||
|
|
}
|
|||
|
|
else if (rootContent is ContentControl contentControl)
|
|||
|
|
{
|
|||
|
|
// 如果根部是 ContentControl,我们需要把原本的内容包在一个新的 Grid 里
|
|||
|
|
var originalContent = contentControl.Content as UIElement;
|
|||
|
|
contentControl.Content = null;
|
|||
|
|
|
|||
|
|
var wrapperGrid = new Grid();
|
|||
|
|
wrapperGrid.Children.Add(originalContent); // 原有内容
|
|||
|
|
wrapperGrid.Children.Add(_view); // 我们的遮罩层
|
|||
|
|
|
|||
|
|
contentControl.Content = wrapperGrid;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 确保遮罩层铺满并置于顶层
|
|||
|
|
Grid.SetColumnSpan(_view, 99);
|
|||
|
|
Grid.SetRowSpan(_view, 99);
|
|||
|
|
Panel.SetZIndex(_view, 9999);
|
|||
|
|
}
|
|||
|
|
// 基础调用:Loading.Show("计算中...");
|
|||
|
|
public static void Show(string msg, bool isIndeterminate, bool canCancel = true) => LoadingService.Instance.Show(msg, canCancel, isIndeterminate);
|
|||
|
|
|
|||
|
|
public static void Hide() => LoadingService.Instance.Hide();
|
|||
|
|
|
|||
|
|
public static void Report(double val) => LoadingService.Instance.Report(val);
|
|||
|
|
|
|||
|
|
// 获取当前令牌:Loading.Token
|
|||
|
|
public static CancellationToken Token => LoadingService.Instance.Token;
|
|||
|
|
|
|||
|
|
// 高级用法:使用 using 块自动开启和关闭
|
|||
|
|
public static IDisposable Manager(string msg, bool canCancel = true)
|
|||
|
|
{
|
|||
|
|
Show(msg, canCancel);
|
|||
|
|
return new DisposableAction(() => Hide());
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static async Task<bool> RunAsync(
|
|||
|
|
Func<CancellationToken, IProgress<double>, Task> work,
|
|||
|
|
string message,
|
|||
|
|
bool canCancel = true, bool isIndeterminate = false,
|
|||
|
|
Action<Exception> onError = null)
|
|||
|
|
{
|
|||
|
|
using (Manager(message, canCancel))
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
LoadingService.Instance.Show(message, isIndeterminate, canCancel);
|
|||
|
|
var progress = new Progress<double>(val =>
|
|||
|
|
Application.Current.Dispatcher.Invoke(() => LoadingService.Instance.ProgressValue = val));
|
|||
|
|
|
|||
|
|
await Task.Run(() => work(LoadingService.Instance.Token, progress), LoadingService.Instance.Token);
|
|||
|
|
|
|||
|
|
return true; // 执行成功
|
|||
|
|
}
|
|||
|
|
catch (OperationCanceledException)
|
|||
|
|
{
|
|||
|
|
// 用户点击了取消,通常不需要弹窗,直接返回 false
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
// 捕获其他所有异常(硬件错误、逻辑错误等)
|
|||
|
|
if (onError != null)
|
|||
|
|
onError(ex);
|
|||
|
|
else
|
|||
|
|
MessageBox.Show($"操作失败: {ex.Message}", "系统错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
|||
|
|
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|