Files
ShrlAlgoToolkit/ShrlAlgo.Addin.Test/ProgressManager.cs

75 lines
2.7 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Threading;
namespace ShrlAlgo.Addin.Test
{
public static class ProgressManager
{
/// <summary>
/// 启动带进度条的 Revit 主线程任务
/// </summary>
/// <param name="title">进度条窗口标题</param>
/// <param name="revitTask">需要在 Revit 主线程执行的任务逻辑</param>
public static void Run(string title, Action<ProgressReporter, CancellationToken> revitTask)
{
var cts = new CancellationTokenSource();
var viewModel = new ProgressViewModel(title, cts);
var reporter = new ProgressReporter(viewModel);
// 使用 ManualResetEvent 等待 WPF 窗口初始化完成
using (var viewReadyEvent = new ManualResetEvent(false))
{
// 1. 创建独立的 STA 线程运行 WPF UI
var uiThread = new Thread(() =>
{
viewModel.UIDispatcher = Dispatcher.CurrentDispatcher;
var window = new ProgressWindow(viewModel);
window.Show();
viewReadyEvent.Set(); // 通知主线程 UI 已就绪
Dispatcher.Run(); // 开启消息循环
});
uiThread.SetApartmentState(ApartmentState.STA); // 必须是 STA
uiThread.IsBackground = true;
uiThread.Start();
viewReadyEvent.WaitOne(); // 阻塞主线程,直到 WPF 窗体显示
// 2. 在 Revit 主线程中执行耗时任务
try
{
revitTask(reporter, cts.Token);
}
catch (OperationCanceledException)
{
// 捕获取消异常,静默处理即可
}
catch (Exception ex)
{
Autodesk.Revit.UI.TaskDialog.Show("Task Error", ex.Message);
}
finally
{
// 3. 任务结束,通知 WPF 线程关闭窗口并停止调度器
if (viewModel.UIDispatcher != null && !viewModel.UIDispatcher.HasShutdownStarted)
{
viewModel.UIDispatcher.InvokeAsync(() =>
{
viewModel.CloseAction?.Invoke();
Dispatcher.CurrentDispatcher.InvokeShutdown();
});
}
uiThread.Join(1000); // 等待 UI 线程彻底退出
cts.Dispose();
}
}
}
}
}