清理ColorPicker,进度条。修复UI问题
This commit is contained in:
@@ -1,41 +0,0 @@
|
||||
using System.Windows.Media;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
|
||||
namespace ShrlAlgoToolkit.RevitAddins.Common.Controls
|
||||
{
|
||||
public partial class ColorPickerViewModel : ObservableObject
|
||||
{
|
||||
public ColorPickerViewModel(Color color)
|
||||
{
|
||||
SelectedColor = color;
|
||||
//this.IsActive = true;
|
||||
//WeakReferenceMessenger.Default.Register<ColorPickerViewModel>(this, (r, m) =>
|
||||
//{
|
||||
// // Handle the message here, with r being the recipient and m being the
|
||||
// // input message. Using the recipient passed as input makes it so that
|
||||
// // the lambda expression doesn't capture "this", improving performance.
|
||||
//});
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
public partial Color SelectedColor { get; set; }
|
||||
|
||||
[RelayCommand]
|
||||
private void Confirm(object obj)
|
||||
{
|
||||
if (obj is System.Windows.Window window)
|
||||
{
|
||||
var colorMessage = new Autodesk.Revit.DB.Color(
|
||||
SelectedColor.R,
|
||||
SelectedColor.G,
|
||||
SelectedColor.B
|
||||
);
|
||||
//发布
|
||||
window.DialogResult = true;
|
||||
WeakReferenceMessenger.Default.Send(colorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
<ui:MelWindow
|
||||
Height="390"
|
||||
Icon="{DynamicResource RevitIcon}"
|
||||
Title="颜色设置"
|
||||
Width="340"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
d:DataContext="{d:DesignInstance Type=windows:ColorPickerViewModel}"
|
||||
mc:Ignorable="d"
|
||||
x:Class="ShrlAlgoToolkit.RevitAddins.Common.Controls.ColorPickerWin"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:ShrlAlgoToolkit.RevitAddins.Common.Controls"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ui="https://github.com/ShrlAlgo/Melskin"
|
||||
xmlns:windows="clr-namespace:ShrlAlgoToolkit.RevitAddins.Common.Controls"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary Source="pack://application:,,,/ShrlAlgoToolkit.RevitAddins;component/WPFUI.xaml" />
|
||||
</Window.Resources>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<!--<controls:StandardColorPicker
|
||||
x:Name="ColorPicker"
|
||||
Grid.ColumnSpan="2"
|
||||
SelectedColor="{Binding SelectedColor, Delay=25, UpdateSourceTrigger=PropertyChanged}">
|
||||
<b:Interaction.Triggers>
|
||||
<b:EventTrigger EventName="MouseLeftButtonUp">
|
||||
<b:InvokeCommandAction Command="{Binding UpdateColorCommand}" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=controls:ColorPicker}}" />
|
||||
</b:EventTrigger>
|
||||
</b:Interaction.Triggers>
|
||||
</controls:StandardColorPicker>-->
|
||||
<ui:ColorPanel
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Grid.Row="0"
|
||||
SelectedColor="{Binding SelectedColor}"
|
||||
x:Name="ColorPicker" />
|
||||
<StackPanel
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Grid.Row="1"
|
||||
HorizontalAlignment="Center"
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
Command="{Binding ConfirmCommand}"
|
||||
CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"
|
||||
Content="确定" />
|
||||
<Button Command="Close" Content="取消" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</ui:MelWindow>
|
||||
@@ -1,13 +0,0 @@
|
||||
namespace ShrlAlgoToolkit.RevitAddins.Common.Controls;
|
||||
|
||||
/// <summary>
|
||||
/// ColorPickerWin.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class ColorPickerWin
|
||||
{
|
||||
public ColorPickerWin(ColorPickerViewModel viewModel)
|
||||
{
|
||||
DataContext = viewModel;
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
using Autodesk.Revit.DB;
|
||||
|
||||
namespace ShrlAlgoToolkit.RevitAddins.Common.Controls
|
||||
{
|
||||
class ProcessEventHandler<T> : IExternalEventHandler
|
||||
{
|
||||
public ProgressMonitorView ProgressBarView { get; set; }
|
||||
public ProgressMonitorViewModel ViewModel { get; set; }
|
||||
public IEnumerable<T> Collection { get; set; }
|
||||
/// <summary>
|
||||
/// 附加的参数,用于传额外的变量
|
||||
/// </summary>
|
||||
public object AddinParameter { get; set; }
|
||||
|
||||
bool Cancel = false;
|
||||
private readonly ExternalEvent externalEvent;
|
||||
private readonly Action<UIApplication, T, object> action;
|
||||
private readonly string transactionName;
|
||||
private readonly bool useTransaction;
|
||||
|
||||
private delegate void ProgressBarDelegate();
|
||||
public ProcessEventHandler(Action<UIApplication, T, object> action, string transactionName = "处理任务", bool useTransaction = true)
|
||||
{
|
||||
externalEvent = ExternalEvent.Create(this);
|
||||
this.action = action;
|
||||
this.transactionName = transactionName;
|
||||
this.useTransaction = useTransaction;
|
||||
}
|
||||
public void Execute(UIApplication app)
|
||||
{
|
||||
if (app == null)
|
||||
{
|
||||
CloseWindow();
|
||||
return;
|
||||
}
|
||||
|
||||
if (app.ActiveUIDocument == null)
|
||||
return;
|
||||
|
||||
if (app.ActiveUIDocument.Document == null)
|
||||
return;
|
||||
|
||||
if (ProgressBarView == null)
|
||||
return;
|
||||
|
||||
if (ViewModel == null)
|
||||
return;
|
||||
Transaction ts = null;
|
||||
// 根据条件决定是否创建并启动事务
|
||||
if (useTransaction)
|
||||
{
|
||||
ts = new(app.ActiveUIDocument.Document, transactionName);
|
||||
ts.Start();
|
||||
}
|
||||
ProgressBarView.btnCancel.Click += CurrentUI_Closed;
|
||||
for (ViewModel.CurrentValue = 0; ViewModel.CurrentValue < ViewModel.MaxValue; ViewModel.CurrentValue++)
|
||||
{
|
||||
System.Threading.Thread.Sleep(20);
|
||||
if (Cancel)
|
||||
break;
|
||||
var elem = Collection.ElementAt(ViewModel.CurrentValue);
|
||||
try
|
||||
{
|
||||
action(app, elem, AddinParameter);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
CloseWindow();
|
||||
// 如果发生异常且事务已启动,则回滚事务
|
||||
if (useTransaction && ts != null)
|
||||
{
|
||||
ts.RollBack();
|
||||
}
|
||||
Common.Assists.LogAssist.ToLog(ex.Message);
|
||||
return;
|
||||
}
|
||||
//await Task.Delay(50);
|
||||
//ViewModel.CurrentContext = $"处理 {ViewModel.CurrentValue} / {ViewModel.MaxValue} 完成";
|
||||
ProgressBarView.Dispatcher.Invoke<string>(() => ViewModel.CurrentContext = $"处理 {ViewModel.CurrentValue} / {ViewModel.MaxValue} 完成", System.Windows.Threading.DispatcherPriority.Background);
|
||||
//ProgressBarView.Dispatcher.Invoke(ViewModel.NotifyUI, System.Windows.Threading.DispatcherPriority.Background);
|
||||
}
|
||||
|
||||
// 根据条件决定是否提交事务
|
||||
if (useTransaction && ts != null)
|
||||
{
|
||||
//取消的时候,回滚,而不是提交部分处理的事务
|
||||
if (Cancel)
|
||||
{
|
||||
ts.RollBack();
|
||||
}
|
||||
else
|
||||
{
|
||||
ts.Commit();
|
||||
}
|
||||
}
|
||||
CloseWindow();
|
||||
// 确保事务对象被正确处理
|
||||
ts?.Dispose();
|
||||
}
|
||||
|
||||
//private async Task Wait()
|
||||
//{
|
||||
// await Task.Delay(50);
|
||||
//}
|
||||
|
||||
private void CloseWindow()
|
||||
{
|
||||
ProgressBarView.Closed -= CurrentUI_Closed;
|
||||
ProgressBarView.Close();
|
||||
//关闭窗口后,需要重设,否则同一个外部事件的Cancel会被上次取消过的情况影响
|
||||
Cancel = false;
|
||||
}
|
||||
|
||||
private void CurrentUI_Closed(object sender, EventArgs e)
|
||||
{
|
||||
Cancel = true;
|
||||
}
|
||||
|
||||
public string GetName()
|
||||
{
|
||||
return "进度监视";
|
||||
}
|
||||
public void Raise()
|
||||
{
|
||||
externalEvent.Raise();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,168 +0,0 @@
|
||||
using Autodesk.Revit.DB;
|
||||
|
||||
namespace ShrlAlgoToolkit.RevitAddins.Common.Controls
|
||||
{
|
||||
class ProgressBarManager<T>
|
||||
{
|
||||
private readonly UIDocument uidoc;
|
||||
private readonly IEnumerable<T> collection;
|
||||
private readonly object addinParameter;
|
||||
private readonly Action<UIDocument, T, object> action;
|
||||
private readonly string taskName;
|
||||
private readonly bool useTransaction;
|
||||
ProgressMonitorViewModel viewModel;
|
||||
ProgressMonitorView progressBarView;
|
||||
|
||||
#region 非模态处理
|
||||
private readonly ProcessEventHandler<T> progressEventHandler;
|
||||
/// <summary>
|
||||
/// 非模态进度条,只能开启一次,请勿在遍历中使用
|
||||
/// </summary>
|
||||
/// <param name="progressEventHandler"></param>
|
||||
/// <param name="collection"></param>
|
||||
public ProgressBarManager(ProcessEventHandler<T> progressEventHandler, IEnumerable<T> collection, string taskName = "处理任务", object addinParameter = null)
|
||||
{
|
||||
this.progressEventHandler = progressEventHandler;
|
||||
progressEventHandler.Collection = collection;
|
||||
progressEventHandler.AddinParameter = addinParameter;
|
||||
this.collection = collection;
|
||||
this.taskName = taskName;
|
||||
}
|
||||
public void ProgressModeless()
|
||||
{
|
||||
if (!progressEventHandler.Collection.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
viewModel = new()
|
||||
{
|
||||
MaxValue = collection.Count(),
|
||||
Title = taskName
|
||||
};
|
||||
|
||||
progressBarView ??= new();
|
||||
//progressBarView = ProgressMonitorView.Instance;
|
||||
progressBarView.DataContext = viewModel;
|
||||
progressBarView.Loaded += CurrentUI_ContentRendered;
|
||||
progressBarView.Closed += CurrentUI_Closed;
|
||||
progressBarView.Topmost = true;
|
||||
//progressEventHandler = new(collection, action)
|
||||
//{
|
||||
// ProgressBarView = progressBarView,
|
||||
// ViewModel = viewModel
|
||||
//};
|
||||
if (collection.Any())
|
||||
{
|
||||
progressEventHandler.ProgressBarView = progressBarView;
|
||||
progressEventHandler.ViewModel = viewModel;
|
||||
//progressBarView.Show();
|
||||
progressBarView.Show();
|
||||
//progressEventHandler.Raise();
|
||||
}
|
||||
|
||||
}
|
||||
private void CurrentUI_ContentRendered(object sender, EventArgs e)
|
||||
{
|
||||
progressEventHandler.Raise();
|
||||
}
|
||||
#endregion
|
||||
#region 模态处理
|
||||
bool Cancel { get; set; }
|
||||
//private delegate void ProgressBarDelegate();
|
||||
/// <summary>
|
||||
/// 模态进度条
|
||||
/// </summary>
|
||||
/// <param name="uidoc"></param>
|
||||
/// <param name="collection"></param>
|
||||
/// <param name="action"></param>
|
||||
public ProgressBarManager(UIDocument uidoc, ICollection<T> collection, Action<UIDocument, T, object> action, string taskName = "处理任务", bool useTransaction = true, object addinParameter = null)
|
||||
{
|
||||
this.uidoc = uidoc;
|
||||
this.collection = collection;
|
||||
this.addinParameter = addinParameter;
|
||||
this.action = action;
|
||||
this.taskName = taskName;
|
||||
this.useTransaction = useTransaction;
|
||||
}
|
||||
public void ProgressModal()
|
||||
{
|
||||
if (!collection.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
viewModel = new ProgressMonitorViewModel
|
||||
{
|
||||
MaxValue = collection.Count(),
|
||||
Title = taskName
|
||||
};
|
||||
progressBarView = new ProgressMonitorView
|
||||
{
|
||||
DataContext = viewModel
|
||||
};
|
||||
//progressBarView = ProgressMonitorView.Instance;
|
||||
//progressBarView.DataContext = viewModel;
|
||||
progressBarView.Closed += CurrentUI_Closed;
|
||||
progressBarView.ContentRendered += FireUPModal;
|
||||
|
||||
progressBarView.ShowDialog();
|
||||
}
|
||||
private async void FireUPModal(object sender, EventArgs e)
|
||||
{
|
||||
progressBarView.ContentRendered -= FireUPModal;
|
||||
Transaction ts = null;
|
||||
// 根据条件决定是否创建并启动事务
|
||||
if (useTransaction)
|
||||
{
|
||||
ts = new Transaction(uidoc.Document, taskName);
|
||||
ts.Start();
|
||||
}
|
||||
for (viewModel.CurrentValue = 0; viewModel.CurrentValue < viewModel.MaxValue; viewModel.CurrentValue++)
|
||||
{
|
||||
if (Cancel)
|
||||
break;
|
||||
|
||||
//System.Threading.Thread.Sleep(50);
|
||||
|
||||
try
|
||||
{
|
||||
var t = collection.ElementAt(viewModel.CurrentValue);
|
||||
//Debug.WriteLine(ViewModel.CurrentValue);
|
||||
action(uidoc, t, addinParameter);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
CloseWindow();
|
||||
// 如果发生异常且事务已启动,则回滚事务
|
||||
if (useTransaction && ts != null && ts.GetStatus() == TransactionStatus.Started)
|
||||
{
|
||||
ts.RollBack();
|
||||
}
|
||||
}
|
||||
viewModel.CurrentContext = $"处理 {viewModel.CurrentValue} / {viewModel.MaxValue} 完成";
|
||||
await Task.Delay(50);
|
||||
//progressBarView.Dispatcher.Invoke(viewModel.NotifyUI, System.Windows.Threading.DispatcherPriority.Background);
|
||||
}
|
||||
// 根据条件决定是否提交事务
|
||||
if (useTransaction && ts != null)
|
||||
{
|
||||
ts.Commit();
|
||||
}
|
||||
|
||||
CloseWindow();
|
||||
// 确保事务对象被正确处理
|
||||
ts?.Dispose();
|
||||
}
|
||||
|
||||
private void CloseWindow()
|
||||
{
|
||||
progressBarView.Closed -= CurrentUI_Closed;
|
||||
progressBarView.Close();
|
||||
}
|
||||
|
||||
private void CurrentUI_Closed(object sender, EventArgs e)
|
||||
{
|
||||
Cancel = true;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Threading;
|
||||
|
||||
|
||||
namespace ShrlAlgoToolkit.RevitAddins.Common.Controls
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
<Window
|
||||
x:Class="ShrlAlgoToolkit.RevitAddins.Common.Controls.ProgressMonitorView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls1="clr-namespace:ShrlAlgoToolkit.RevitAddins.Common.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:windows="clr-namespace:ShrlAlgoToolkit.RevitAddins.Common.Controls"
|
||||
Title="{Binding Title}"
|
||||
d:DataContext="{d:DesignInstance Type=windows:ProgressMonitorViewModel}"
|
||||
Background="{DynamicResource MaterialDesign.Brush.Background}"
|
||||
Icon="{DynamicResource RevitIcon}"
|
||||
ResizeMode="NoResize"
|
||||
SizeToContent="WidthAndHeight"
|
||||
TextElement.Foreground="{DynamicResource MaterialDesign.Brush.Foreground}"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
mc:Ignorable="d">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary Source="pack://application:,,,/ShrlAlgoToolkit.RevitAddins;component/WPFUI.xaml" />
|
||||
</Window.Resources>
|
||||
<StackPanel Margin="10">
|
||||
<TextBlock Text="{Binding CurrentContext}" />
|
||||
<Separator />
|
||||
<ProgressBar
|
||||
Width="300"
|
||||
Height="23"
|
||||
Maximum="{Binding MaxValue}"
|
||||
Value="{Binding CurrentValue}" />
|
||||
<Separator />
|
||||
<Button
|
||||
x:Name="btnCancel"
|
||||
HorizontalAlignment="Right"
|
||||
Content="取消"
|
||||
IsCancel="True" />
|
||||
</StackPanel>
|
||||
</Window>
|
||||
@@ -1,25 +0,0 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace ShrlAlgoToolkit.RevitAddins.Common.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ProgressMonitorView.xaml
|
||||
/// </summary>
|
||||
public partial class ProgressMonitorView : Window
|
||||
{
|
||||
public ProgressMonitorView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
//private static ProgressMonitorView instance;
|
||||
|
||||
//public static ProgressMonitorView Instance
|
||||
//{
|
||||
// get
|
||||
// {
|
||||
// instance ??= new ProgressMonitorView();
|
||||
// return instance;
|
||||
// }
|
||||
//}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
namespace ShrlAlgoToolkit.RevitAddins.Common.Controls
|
||||
{
|
||||
partial class ProgressMonitorViewModel : ObservableObject
|
||||
{
|
||||
[ObservableProperty]
|
||||
public partial int MaxValue { get; set; } = 100;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial int CurrentValue { get; set; } = 0;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial string CurrentContext { get; set; } = string.Empty;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial string Title { get; set; } = "处理任务";
|
||||
|
||||
public void NotifyUI()
|
||||
{
|
||||
var classType = this.GetType();
|
||||
if (classType != null)
|
||||
{
|
||||
var currentProperties = classType.GetProperties();
|
||||
foreach (var currentProperty in currentProperties)
|
||||
OnPropertyChanged(currentProperty.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace ShrlAlgoToolkit.RevitAddins.Common.Controls
|
||||
{
|
||||
// 用于给外界调用的报告器
|
||||
public class ProgressReporter
|
||||
{
|
||||
private readonly ProgressViewModel _viewModel;
|
||||
private DateTime _lastUpdate = DateTime.MinValue;
|
||||
|
||||
public ProgressReporter(ProgressViewModel viewModel)
|
||||
{
|
||||
_viewModel = viewModel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新进度 (自带节流控制,防止频繁更新导致UI卡顿)
|
||||
/// </summary>
|
||||
public void Report(int current, int total, string message = null)
|
||||
{
|
||||
// 限制 UI 刷新频率(每 50 毫秒最多刷新一次)
|
||||
if ((DateTime.Now - _lastUpdate).TotalMilliseconds < 50 && current != total)
|
||||
return;
|
||||
|
||||
_lastUpdate = DateTime.Now;
|
||||
_viewModel.Update(current, total, message);
|
||||
}
|
||||
|
||||
public void ReportMessage(string message) => _viewModel.UpdateMessage(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace ShrlAlgoToolkit.RevitAddins.Common.Controls
|
||||
{
|
||||
// WPF 的 ViewModel
|
||||
public class ProgressViewModel : INotifyPropertyChanged
|
||||
{
|
||||
private readonly CancellationTokenSource _cts;
|
||||
public Dispatcher UIDispatcher { get; set; }
|
||||
public Action CloseAction { get; set; }
|
||||
|
||||
public ProgressViewModel(string title, CancellationTokenSource cts)
|
||||
{
|
||||
Title = title;
|
||||
_cts = cts;
|
||||
}
|
||||
|
||||
private string _title;
|
||||
public string Title { get => _title; set => SetProperty(ref _title, value); }
|
||||
|
||||
private string _message = "正在准备...";
|
||||
public string Message { get => _message; set => SetProperty(ref _message, value); }
|
||||
|
||||
private double _progressValue;
|
||||
public double ProgressValue { get => _progressValue; set => SetProperty(ref _progressValue, value); }
|
||||
|
||||
private double _maximum = 100;
|
||||
public double Maximum { get => _maximum; set => SetProperty(ref _maximum, value); }
|
||||
|
||||
public void Cancel()
|
||||
{
|
||||
if (!_cts.IsCancellationRequested)
|
||||
{
|
||||
Message = "正在取消任务,请稍候...";
|
||||
_cts.Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
// 跨线程更新 UI
|
||||
public void Update(int current, int total, string message)
|
||||
{
|
||||
UIDispatcher?.InvokeAsync(() =>
|
||||
{
|
||||
ProgressValue = current;
|
||||
Maximum = total;
|
||||
if (!string.IsNullOrEmpty(message)) Message = message;
|
||||
});
|
||||
}
|
||||
|
||||
public void UpdateMessage(string message)
|
||||
{
|
||||
UIDispatcher?.InvokeAsync(() => Message = message);
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
protected void SetProperty<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
|
||||
{
|
||||
field = value;
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<Window
|
||||
x:Class="ShrlAlgoToolkit.RevitAddins.Common.Controls.ProgressWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local1="clr-namespace:ShrlAlgoToolkit.RevitAddins.Common.Controls"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
Title="{Binding Title}"
|
||||
Width="450"
|
||||
Height="180"
|
||||
d:DataContext="{d:DesignInstance Type=local1:ProgressViewModel}"
|
||||
ResizeMode="NoResize"
|
||||
ShowInTaskbar="False"
|
||||
Topmost="True"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
WindowStyle="ToolWindow"
|
||||
mc:Ignorable="d">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary Source="pack://application:,,,/ShrlAlgoToolkit.RevitAddins;component/WPFUI.xaml" />
|
||||
</Window.Resources>
|
||||
<Grid Margin="20">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- 状态文本 -->
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Margin="0,0,0,10"
|
||||
FontSize="14"
|
||||
Text="{Binding Message}"
|
||||
TextTrimming="CharacterEllipsis" />
|
||||
|
||||
<!-- 进度条 -->
|
||||
<ProgressBar
|
||||
Grid.Row="1"
|
||||
Height="25"
|
||||
Maximum="{Binding Maximum}"
|
||||
Value="{Binding ProgressValue}" />
|
||||
|
||||
<!-- 进度数字与取消按钮 -->
|
||||
<Grid Grid.Row="2" Margin="0,15,0,0">
|
||||
<TextBlock VerticalAlignment="Center" Foreground="Gray">
|
||||
<Run Text="{Binding ProgressValue, Mode=OneWay, StringFormat={}{0:0}}" />
|
||||
<Run Text=" / " />
|
||||
<Run Text="{Binding Maximum, Mode=OneWay, StringFormat={}{0:0}}" />
|
||||
</TextBlock>
|
||||
|
||||
<Button
|
||||
Width="80"
|
||||
HorizontalAlignment="Right"
|
||||
Click="BtnCancel_Click"
|
||||
Content="取 消" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
|
||||
namespace ShrlAlgoToolkit.RevitAddins.Common.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// ProgressWindow.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class ProgressWindow : Window
|
||||
{
|
||||
private readonly ProgressViewModel _viewModel;
|
||||
|
||||
public ProgressWindow(ProgressViewModel viewModel)
|
||||
{
|
||||
InitializeComponent();
|
||||
_viewModel = viewModel;
|
||||
DataContext = _viewModel;
|
||||
|
||||
// 绑定关闭委托
|
||||
_viewModel.CloseAction = this.Close;
|
||||
}
|
||||
|
||||
private void BtnCancel_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_viewModel.Cancel();
|
||||
(sender as System.Windows.Controls.Button).IsEnabled = false;
|
||||
}
|
||||
|
||||
// 屏蔽系统的 Alt+F4 关闭,强制必须等主线程任务结束
|
||||
protected override void OnClosing(CancelEventArgs e)
|
||||
{
|
||||
if (!_viewModel.UIDispatcher.HasShutdownStarted)
|
||||
{
|
||||
e.Cancel = true;
|
||||
_viewModel.Cancel(); // 尝试取消
|
||||
}
|
||||
base.OnClosing(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user