75 lines
2.7 KiB
C#
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();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|