调整代码

This commit is contained in:
GG Z
2026-02-22 20:03:42 +08:00
parent 2ad3d0fde0
commit 7e2d5be3cd
258 changed files with 2916 additions and 5013 deletions

View File

@@ -0,0 +1,41 @@
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);
}
}
}
}

View File

@@ -0,0 +1,59 @@
<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>

View File

@@ -0,0 +1,13 @@
namespace ShrlAlgoToolkit.RevitAddins.Common.Controls;
/// <summary>
/// ColorPickerWin.xaml 的交互逻辑
/// </summary>
public partial class ColorPickerWin
{
public ColorPickerWin(ColorPickerViewModel viewModel)
{
DataContext = viewModel;
InitializeComponent();
}
}

View File

@@ -0,0 +1,24 @@
using Autodesk.Revit.DB;
namespace ShrlAlgoToolkit.RevitAddins.Common.Controls;
/// <summary>
/// 错误的条目
/// </summary>
public class MessageModel
{
public MessageModel(Element element, string errorMessage)
{
Element = element;
ErrorMessage = errorMessage;
}
public Element Element { get; }
public object Group { get; set; }
public bool IsInstance => Element.CanHaveTypeAssigned() && Element.HasPhases();
public string ErrorMessage { get; }
}

View File

@@ -0,0 +1,85 @@
using Autodesk.Revit.DB;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Nice3point.Revit.Toolkit.External.Handlers;
namespace ShrlAlgoToolkit.RevitAddins.Common.Controls;
public partial class MessageViewModel : ObservableObject
{
public MessageViewModel(UIDocument uidoc, List<MessageModel> errorModels, string winTitle = "错误处理")
{
this.uidoc = uidoc;
showElementsSectionBox = new ActionEventHandler();
ErrorModels.AddRange(errorModels);
WinTitle = winTitle;
Count = errorModels.Count();
}
[ObservableProperty]
public partial string Footer { get; set; }
private readonly UIDocument uidoc;
[ObservableProperty]
public partial List<MessageModel> ErrorModels { get; set; } = [];
[ObservableProperty]
public partial string WinTitle { get; set; }
[ObservableProperty]
public partial int Count { get; set; }
private readonly ActionEventHandler showElementsSectionBox;
[RelayCommand]
private void ShowElement(object obj)
{
if (obj is not MessageModel model)
{
return;
}
var doc = uidoc.Document;
//if (UiDocument.ActiveView.IsTemporaryHideIsolateActive())
//{
// UiDocument.ActiveView.temporary
//}
if (model.Element.IsValidObject)
{
if (model.Element.IsHidden(uidoc.ActiveView))
{
return;
}
var ids = new List<ElementId> { model.Element.Id };
//UiDocument.ActiveView.IsolateElementTemporary(model.ElementToMove.ViewId);
showElementsSectionBox.Raise(
_ =>
{
if (uidoc.ActiveView is not View3D view3d)
{
view3d = doc.OfClass<View3D>().FirstElement() as View3D;
}
if (!model.Element.ViewSpecific)
{
uidoc.ActiveView = view3d;
}
doc.Invoke(
_ =>
{
if (uidoc.ActiveView is View3D)
{
view3d.SectionBoxElements(ids);
}
view3d.ZoomElements(uidoc, ids);
uidoc.Selection.SetElementIds(ids);
});
});
}
else
{
ErrorModels.Remove(model);
}
}
}

View File

@@ -0,0 +1,61 @@
<ui:MelWindow
Height="450"
Icon="{DynamicResource RevitIcon}"
Title="{Binding WinTitle}"
Width="800"
d:DataContext="{d:DesignInstance Type=windows:MessageViewModel}"
mc:Ignorable="d"
x:Class="ShrlAlgoToolkit.RevitAddins.Common.Controls.MessageWin"
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>
<!--<Window.DataContext>
<local:ErrorResolveViewModel />
</Window.DataContext>-->
<ui:StackPanel Margin="5" Spacing="5">
<DataGrid
AutoGenerateColumns="False"
CanUserAddRows="False"
IsReadOnly="True"
ItemsSource="{Binding ErrorModels}"
ToolTip="双击行可快速定位"
ui:StackPanel.Fill="Fill">
<b:Interaction.Triggers>
<b:EventTrigger EventName="MouseDoubleClick">
<b:InvokeCommandAction Command="{Binding ShowElementCommand}" CommandParameter="{Binding SelectedItem, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid}}" />
</b:EventTrigger>
</b:Interaction.Triggers>
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Element.Category.Name}" Header="类别名称" />
<DataGridTextColumn Binding="{Binding Element.Name}" Header="元素名称" />
<DataGridTextColumn Binding="{Binding Host.Name}" Header="主体" />
<DataGridTextColumn Binding="{Binding Element.Id}" Header="元素Id" />
<DataGridTextColumn Binding="{Binding ErrorMessage}" Header="错误信息" />
<DataGridTemplateColumn Header="操作">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<!-- 按钮参数绑定到当前行的绑定的Item -->
<Button
Command="{Binding DataContext.ShowElementCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid}}"
CommandParameter="{Binding}"
Content="定位构件" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
<ui:StackPanel Grid.Row="1" Orientation="Horizontal">
<ui:Heading Text="注:错误需人处理、或无法处理" ui:StackPanel.Fill="Fill" />
<TextBlock Text="{Binding Count, StringFormat=错误数量:{0}}" />
<TextBlock Text="{Binding Footer}" />
</ui:StackPanel>
</ui:StackPanel>
</ui:MelWindow>

View File

@@ -0,0 +1,15 @@
using Melskin.Controls;
namespace ShrlAlgoToolkit.RevitAddins.Common.Controls
{
/// <summary>
/// MessageWin.xaml 的交互逻辑
/// </summary>
public sealed partial class MessageWin : MelWindow
{
public MessageWin()
{
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,32 @@
using Autodesk.Revit.DB;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
namespace ShrlAlgoToolkit.RevitAddins.Common.Controls
{
public partial class NavigateViewViewModel : ObservableObject
{
public NavigateViewViewModel(UIApplication uiapp, params Type[] viewTypes)
{
var doc = uiapp.ActiveUIDocument.Document;
Views = doc.OfClasses(viewTypes).Cast<View>().Where(v => !v.IsTemplate).ToList();
this.uiapp = uiapp;
}
private readonly UIApplication uiapp;
[ObservableProperty]
public partial IList<View> Views { get; set; }
[RelayCommand]
private void NavigateView(object obj)
{
if (obj is View view)
{
var uidoc = uiapp.ActiveUIDocument;
uidoc.ActiveView = view;
}
}
}
}

View File

@@ -0,0 +1,29 @@
<ui:MelWindow
Height="200"
Icon="{DynamicResource RevitIcon}"
Title="选择视图"
Width="300"
d:DataContext="{d:DesignInstance Type=windows:NavigateViewViewModel}"
mc:Ignorable="d"
x:Class="ShrlAlgoToolkit.RevitAddins.Common.Controls.NavigateViewWin"
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>
<ListBox DisplayMemberPath="Name" ItemsSource="{Binding Views}">
<b:Interaction.Triggers>
<b:EventTrigger EventName="MouseDoubleClick">
<b:InvokeCommandAction Command="{Binding NavigateViewCommand}" CommandParameter="{Binding SelectedItem, RelativeSource={RelativeSource FindAncestor, AncestorType=ListBox}}" />
</b:EventTrigger>
</b:Interaction.Triggers>
</ListBox>
</Grid>
</ui:MelWindow>

View File

@@ -0,0 +1,14 @@
namespace ShrlAlgoToolkit.RevitAddins.Common.Controls
{
/// <summary>
/// NavigateViewWin.xaml 的交互逻辑
/// </summary>
public partial class NavigateViewWin
{
public NavigateViewWin(NavigateViewViewModel viewModel)
{
DataContext = viewModel;
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,128 @@
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();
}
}
}

View File

@@ -0,0 +1,168 @@
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
}
}

View File

@@ -0,0 +1,36 @@
<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>

View File

@@ -0,0 +1,25 @@
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;
// }
//}
}
}

View File

@@ -0,0 +1,30 @@
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);
}
}
}
}