774 lines
31 KiB
C#
774 lines
31 KiB
C#
using System.Collections;
|
||
using System.Collections.ObjectModel;
|
||
using System.ComponentModel;
|
||
using System.Linq;
|
||
using System.Text;
|
||
using System.Text.RegularExpressions;
|
||
using System.Windows;
|
||
using System.Windows.Data;
|
||
|
||
using Autodesk.Revit.DB;
|
||
|
||
using EPPlus.Core.Extensions;
|
||
using EPPlus.Core.Extensions.Attributes;
|
||
|
||
using FuzzySharp;
|
||
|
||
using Nice3point.Revit.Toolkit.External.Handlers;
|
||
using Nice3point.Revit.Toolkit.Helpers;
|
||
|
||
using OfficeOpenXml;
|
||
|
||
namespace Szmedi.RvKits.MEPTools
|
||
{
|
||
public partial class FacilityInfoProcessViewModel : ObservableObject
|
||
{
|
||
private readonly ActionEventHandler handler;
|
||
|
||
[ObservableProperty]
|
||
public partial string SearchText { get; set; }
|
||
partial void OnSearchTextChanged(string value)
|
||
{
|
||
FacilitiesCollectionView.Refresh();
|
||
}
|
||
[ObservableProperty]
|
||
public partial bool ContainsAllLines { get; set; }
|
||
partial void OnContainsAllLinesChanged(bool value)
|
||
{
|
||
FacilitiesCollectionView.Refresh();
|
||
}
|
||
[ObservableProperty]
|
||
public partial List<FacilityItem> Items { get; set; }
|
||
[ObservableProperty]
|
||
public partial string SearchInstanceText { get; set; }
|
||
partial void OnSearchInstanceTextChanged(string value)
|
||
{
|
||
InstancesCollectionView.Refresh();
|
||
}
|
||
|
||
private List<Family> Families { get; set; } = [];
|
||
public ICollectionView FacilitiesCollectionView { get; set; }
|
||
public ICollectionView InstancesCollectionView { get; set; }
|
||
public FacilityInfoProcessViewModel()
|
||
{
|
||
GlobalVariables.UIApplication?.ViewActivated += UIApplication_ViewActivated;
|
||
handler = new ActionEventHandler();
|
||
}
|
||
[RelayCommand]
|
||
private void ProcessExcel(string filePath)
|
||
{
|
||
FileInfo fi = new(filePath);
|
||
|
||
using ExcelPackage package = new(fi);
|
||
AppDomain.CurrentDomain.AssemblyResolve += ResolveHelper.ResolveAssembly;
|
||
try
|
||
{
|
||
Items = package.ToList<FacilityItem>(1, configuration => configuration.SkipCastingErrors());
|
||
}
|
||
catch (EPPlus.Core.Extensions.Exceptions.ExcelValidationException ex)
|
||
{
|
||
MessageBox.Show("列名不存在或不匹配,请检查表头是否存在换行或多余文字。", ex.Message);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
MessageBox.Show(ex.Message);
|
||
}
|
||
finally
|
||
{
|
||
AppDomain.CurrentDomain.AssemblyResolve -= ResolveHelper.ResolveAssembly;
|
||
}
|
||
}
|
||
|
||
private void UIApplication_ViewActivated(object sender, Autodesk.Revit.UI.Events.ViewActivatedEventArgs e)
|
||
{
|
||
GetFamilies();
|
||
FuzzyMatch();
|
||
}
|
||
|
||
//private Assembly CurrentDomainOnAssemblyResolve(object sender, ResolveEventArgs args)
|
||
//{
|
||
// if (args.Name.Contains("ComponentModel.Annotations"))
|
||
// {
|
||
// var assemblyFile = Path.Combine(GlobalVariables.DirAssembly, "System.ComponentModel.Annotations.dll");
|
||
// return File.Exists(assemblyFile) ? Assembly.LoadFrom(assemblyFile) : null;
|
||
|
||
// }
|
||
// if (args.Name.Contains("EPPlus"))
|
||
// {
|
||
// var epplusFile = Path.Combine(GlobalVariables.DirAssembly, "EPPlus.dll");
|
||
// return File.Exists(epplusFile) ? Assembly.LoadFrom(epplusFile) : null;
|
||
// }
|
||
// return null;
|
||
|
||
//}
|
||
|
||
public List<Family> GetUsedFamilies(Document doc)
|
||
{
|
||
// 获取所有实例元素(这里不需要由ToElements()转化全部对象,节省内存,仅遍历)
|
||
var instances = doc.OfClass<FamilyInstance>();
|
||
|
||
// 3. 收集所有被使用的“类型ID” (使用HashSet自动去重)
|
||
HashSet<ElementId> usedTypeIds = new HashSet<ElementId>();
|
||
|
||
foreach (Element elem in instances)
|
||
{
|
||
ElementId typeId = elem.GetTypeId();
|
||
if (typeId != ElementId.InvalidElementId)
|
||
{
|
||
usedTypeIds.Add(typeId);
|
||
}
|
||
}
|
||
|
||
// 4. 从类型反向获取族 (使用HashSet再次去重族ID,防止多个类型属于同一个族)
|
||
HashSet<ElementId> usedFamilyIds = new HashSet<ElementId>();
|
||
List<Family> resultFamilies = new List<Family>();
|
||
|
||
foreach (ElementId typeId in usedTypeIds)
|
||
{
|
||
// 获取类型元素 (FamilySymbol)
|
||
Element typeElem = doc.GetElement(typeId);
|
||
|
||
if (typeElem is FamilySymbol symbol)
|
||
{
|
||
Family family = symbol.Family;
|
||
|
||
// 确保族存在且未被添加过
|
||
if (family != null && usedFamilyIds.Add(family.Id))
|
||
{
|
||
resultFamilies.Add(family);
|
||
}
|
||
}
|
||
}
|
||
|
||
return resultFamilies;
|
||
}
|
||
private void GetFamilies()
|
||
{
|
||
var doc = GlobalVariables.UIApplication.ActiveUIDocument.Document;
|
||
if (doc.IsFamilyDocument)
|
||
{
|
||
return;
|
||
}
|
||
var families = GetUsedFamilies(doc)
|
||
.Where(
|
||
fam => fam.FamilyCategory.AllowsBoundParameters &&
|
||
fam.IsEditable &&
|
||
fam.FamilyCategory.CategoryType == CategoryType.Model &&
|
||
!Enum.GetName(typeof(BuiltInCategory), fam.FamilyCategoryId.IntegerValue)!.Contains(
|
||
"Fitting") &&
|
||
fam.FamilyCategoryId.IntegerValue != -2008013);//风道末端
|
||
|
||
Families = [.. families];
|
||
}
|
||
[ObservableProperty]
|
||
public partial string ExcelPath { get; set; }
|
||
[RelayCommand]
|
||
private void BrowserExcel()
|
||
{
|
||
var ofd = new Microsoft.Win32.OpenFileDialog
|
||
{
|
||
Filter = "Excel 文件 (*.xlsx;*.xls)|*.xlsx;*.xls",
|
||
Title = "选择 Excel 文件"
|
||
};
|
||
bool? result = ofd.ShowDialog();
|
||
if (result == true)
|
||
{
|
||
GetFamilies();
|
||
ExcelPath = ofd.FileName;
|
||
ProcessExcel(ofd.FileName);
|
||
if (Items == null)
|
||
{
|
||
return;
|
||
}
|
||
FuzzyMatch();
|
||
FacilitiesCollectionView = CollectionViewSource.GetDefaultView(Items);
|
||
|
||
FacilitiesCollectionView.Filter = o =>
|
||
{
|
||
if (string.IsNullOrEmpty(SearchText))
|
||
return true;
|
||
if (o is FacilityItem info)
|
||
{
|
||
//var title = GlobalVariables.UIApplication.ActiveUIDocument.Document.Title;
|
||
//var match = Regex.Match(title, @"(?<=^\d+号线-)([^-]+?)(?=车辆段|站|区间|停车场|主变电|变电所)");
|
||
//string result = match.Success ? match.Value : string.Empty;
|
||
return info.ToString().Contains(SearchText) || (ContainsAllLines && info.ToString().Contains("全线"));
|
||
}
|
||
return false;
|
||
};
|
||
}
|
||
}
|
||
private void FuzzyMatch()
|
||
{
|
||
if (Items == null || Families == null)
|
||
{
|
||
return;
|
||
}
|
||
foreach (var item in Items)
|
||
{
|
||
double minRatio = 30;
|
||
|
||
foreach (var family in Families)
|
||
{
|
||
var famName = family.Name;
|
||
var tempRatio = Fuzz.TokenSetRatio(famName, item.Name);
|
||
if (tempRatio >= minRatio)
|
||
{
|
||
minRatio = tempRatio;
|
||
item.MappedFamily = family;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
public bool? IsAllItemsSelected
|
||
{
|
||
get
|
||
{
|
||
var selected = Items?.Select(item => item.IsSelected).Distinct().ToList();
|
||
if (selected == null)
|
||
{
|
||
return false;
|
||
}
|
||
return selected.Count == 1 ? selected.Single() : null;
|
||
}
|
||
set
|
||
{
|
||
if (value.HasValue)
|
||
{
|
||
SelectAll(value.Value, Items);
|
||
OnPropertyChanged();
|
||
}
|
||
}
|
||
}
|
||
private static void SelectAll(bool select, IEnumerable<FacilityItem> models)
|
||
{
|
||
foreach (var model in models)
|
||
{
|
||
model.IsSelected = select;
|
||
}
|
||
}
|
||
[NotifyCanExecuteChangedFor(nameof(SelectInstanceCommand))]
|
||
[ObservableProperty]
|
||
private partial bool CanSelecting { get; set; } = true;
|
||
/// <summary>
|
||
/// 提取字符串中所有中文字符
|
||
/// </summary>
|
||
private static string ExtractChinese(string text)
|
||
{
|
||
if (string.IsNullOrEmpty(text)) return string.Empty;
|
||
|
||
// 先将非中文替换为空格,再将连续空格替换为单个空格,最后去除首尾空格
|
||
var result = Regex.Replace(text, @"[^\u4e00-\u9fa5]", " ");
|
||
result = Regex.Replace(result, @"\s+", " ").Trim();
|
||
return result;
|
||
}
|
||
[RelayCommand(CanExecute = nameof(CanSelecting))]
|
||
private void SelectInstance(FacilityItem item)
|
||
{
|
||
CanSelecting = false;
|
||
try
|
||
{
|
||
var uidoc = GlobalVariables.UIApplication.ActiveUIDocument;
|
||
var reference = uidoc.Selection
|
||
.PickObject(
|
||
Autodesk.Revit.UI.Selection.ObjectType.Element,
|
||
new FuncFilter(
|
||
e => e is FamilyInstance instance &&
|
||
instance.Category != null &&
|
||
!instance.Symbol.Family.IsCurtainPanelFamily &&
|
||
instance.Symbol.Family.IsUserCreated &&
|
||
instance.Symbol.Family.IsEditable &&
|
||
!Enum.GetName(typeof(BuiltInCategory), instance.Category.Id.IntegerValue)!.Contains("Fitting") &&
|
||
instance.Category.CategoryType == CategoryType.Model &&
|
||
instance.Category.Id.IntegerValue != -2008013),
|
||
"请选择关联的族实例");
|
||
var instance = uidoc.Document.GetElement(reference) as FamilyInstance;
|
||
item.MappedFamily = instance.Symbol.Family;
|
||
}
|
||
catch (Autodesk.Revit.Exceptions.OperationCanceledException)
|
||
{
|
||
}
|
||
finally
|
||
{
|
||
CanSelecting = true;
|
||
}
|
||
}
|
||
public static string ValidateDuplicatesWithDisplay<T>(
|
||
IEnumerable<T> items,
|
||
Func<T, object> keySelector, // 用于判断重复的键(如 ID)
|
||
Func<T, string> displaySelector // 用于显示的文本(如 Name 或组合)
|
||
)
|
||
{
|
||
if (items == null)
|
||
return "数据为空。";
|
||
|
||
var keyToDisplay = new Dictionary<object, string>(new ObjectKeyComparer());
|
||
var duplicates = new List<string>();
|
||
|
||
foreach (var item in items)
|
||
{
|
||
if (item == null) continue;
|
||
|
||
var key = keySelector(item);
|
||
var display = displaySelector(item) ?? "(空)";
|
||
|
||
// 如果键已存在,说明重复,记录显示文本
|
||
if (keyToDisplay.TryGetValue(key, out var existingDisplay))
|
||
{
|
||
// 避免重复添加相同项的提示(可选)
|
||
if (!duplicates.Contains(display) && !duplicates.Contains(existingDisplay))
|
||
{
|
||
duplicates.Add($"[{existingDisplay} 与 {display}]");
|
||
}
|
||
}
|
||
else
|
||
{
|
||
keyToDisplay[key] = display;
|
||
}
|
||
}
|
||
|
||
if (duplicates.Count > 0)
|
||
return $"发现重复的项,可能包含:{string.Join(";", duplicates)}";
|
||
|
||
return string.Empty;
|
||
}
|
||
// 辅助类:解决 object 作为 key 时的 null 和类型一致性问题
|
||
class ObjectKeyComparer : IEqualityComparer<object>
|
||
{
|
||
public new bool Equals(object x, object y)
|
||
{
|
||
if (x == null && y == null) return true;
|
||
if (x == null || y == null) return false;
|
||
return x.Equals(y);
|
||
}
|
||
|
||
public int GetHashCode(object obj) => obj?.GetHashCode() ?? 0;
|
||
}
|
||
[RelayCommand]
|
||
private void ProcessModelInfo()
|
||
{
|
||
var processItems = Items.Where(i => i.IsSelected && i.MappedFamily != null && i.Instances.Count > 0).ToList();
|
||
if (processItems.Count == 0)
|
||
{
|
||
MessageBox.Show("未选择任何有效的设备项进行处理。", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
||
return;
|
||
}
|
||
|
||
handler.Raise(
|
||
uiapp =>
|
||
{
|
||
var doc = uiapp.ActiveUIDocument.Document;
|
||
if (doc.IsFamilyDocument)
|
||
{
|
||
return;
|
||
}
|
||
doc.InvokeGroup(
|
||
_ =>
|
||
{
|
||
StringBuilder sb = new StringBuilder();
|
||
var allInstances = Items.Where(i => i.IsSelected).SelectMany(i => i.Instances).ToList();
|
||
string message = ValidateDuplicatesWithDisplay(allInstances, s => s.Id, s => $"{s.Symbol.FamilyName}:{s.Name}");
|
||
if (!string.IsNullOrEmpty(message))
|
||
{
|
||
MessageBox.Show(message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||
return;
|
||
}
|
||
foreach (var item in processItems)
|
||
{
|
||
var family = item.MappedFamily;
|
||
if (!family.IsValidObject)
|
||
{
|
||
sb.AppendLine($"<{item.Name}>因文档手动修改导致匹配族失效,请重新匹配,跳过该族。");
|
||
continue;
|
||
}
|
||
if (!family.IsEditable)
|
||
{
|
||
sb.AppendLine($"{family.Name} 族不可编辑,跳过该族。");
|
||
continue;
|
||
}
|
||
Document famdoc = null;
|
||
try
|
||
{
|
||
famdoc = doc.EditFamily(family);
|
||
famdoc.Invoke(
|
||
_ =>
|
||
{
|
||
foreach (var paramItem in item.Parameters)
|
||
{
|
||
try
|
||
{
|
||
var familyParameters = famdoc.FamilyManager.GetParameters()
|
||
.Where(p => p.Definition.Name == paramItem.Name).ToList();
|
||
if (familyParameters.Count > 0)
|
||
{
|
||
var parameter = familyParameters.FirstOrDefault();
|
||
|
||
if (parameter.Definition is InternalDefinition def && def.BuiltInParameter == BuiltInParameter.INVALID)
|
||
{
|
||
famdoc.FamilyManager.RemoveParameter(parameter);
|
||
famdoc.Regenerate();
|
||
}
|
||
|
||
famdoc.FamilyManager.AddParameter(paramItem.Name, BuiltInParameterGroup.PG_TEXT, ParameterType.Text, true);
|
||
}
|
||
else
|
||
{
|
||
famdoc.FamilyManager
|
||
.AddParameter(
|
||
paramItem.Name,
|
||
BuiltInParameterGroup.PG_TEXT,
|
||
ParameterType.Text,
|
||
true);
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
sb.AppendLine($"{family.Name} 族参数 {paramItem.Name} 添加失败,{ex.Message}");
|
||
}
|
||
|
||
}
|
||
|
||
},
|
||
"添加缺失的族参数属性条目");
|
||
|
||
item.MappedFamily = famdoc.LoadFamily(doc, new FamilyLoadOption());
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
sb.AppendLine($"{family.Name} 族加载到项目中失败,原因:{ex.Message}");
|
||
}
|
||
finally
|
||
{
|
||
famdoc?.Close(false);
|
||
}
|
||
doc.Invoke(
|
||
ts =>
|
||
{
|
||
foreach (var instance in item.Instances)
|
||
{
|
||
foreach (var paramItem in item.Parameters)
|
||
{
|
||
Parameter param = instance.GetParameters(paramItem.Name)?.FirstOrDefault();
|
||
if (param is { IsReadOnly: false })
|
||
{
|
||
param.Set(paramItem.Value);
|
||
}
|
||
else
|
||
{
|
||
sb.AppendLine($"{instance.Id} - {instance.Name} 未找到参数 {paramItem.Name} 或参数只读,未设置其值。");
|
||
}
|
||
}
|
||
|
||
}
|
||
});
|
||
}
|
||
|
||
MessageBox.Show(sb.Length > 0 ? sb.ToString() : "添加完成!");
|
||
}, "处理设备信息");
|
||
|
||
});
|
||
}
|
||
[ObservableProperty]
|
||
public partial FacilityItem SelectedFacility { get; set; }
|
||
|
||
partial void OnSelectedFacilityChanged(FacilityItem value)
|
||
{
|
||
if (value != null)
|
||
{
|
||
InstancesCollectionView = CollectionViewSource.GetDefaultView(value.Instances);
|
||
InstancesCollectionView.Filter = o =>
|
||
{
|
||
if (string.IsNullOrEmpty(SearchInstanceText))
|
||
return true;
|
||
if (o is FamilyInstance ins)
|
||
{
|
||
return ins.Name.Contains(SearchInstanceText);
|
||
}
|
||
return false;
|
||
};
|
||
}
|
||
}
|
||
|
||
[RelayCommand]
|
||
private void LocationInstance(FamilyInstance instance)
|
||
{
|
||
var uidoc = GlobalVariables.UIApplication.ActiveUIDocument;
|
||
if (uidoc.Document.GetElement(instance.Id).IsValidObject)
|
||
{
|
||
uidoc.Selection.SetElementIds([instance.Id]);
|
||
uidoc.ShowElements(instance);
|
||
}
|
||
}
|
||
|
||
[RelayCommand]
|
||
private void RemoveInstance(FamilyInstance instance)
|
||
{
|
||
SelectedFacility?.Instances.Remove(instance);
|
||
}
|
||
|
||
[RelayCommand]
|
||
private void RemoveSelectedInstances(IList list)
|
||
{
|
||
if (SelectedFacility?.Instances == null || list == null)
|
||
return;
|
||
|
||
//先找出所有需要移除的项(不修改原集合)
|
||
var toRemove = new List<FamilyInstance>();
|
||
foreach (var item in list)
|
||
{
|
||
if (item is FamilyInstance instance &&
|
||
SelectedFacility.Instances.Contains(instance))
|
||
{
|
||
toRemove.Add(instance);
|
||
}
|
||
}
|
||
|
||
foreach (var instance in toRemove)
|
||
{
|
||
SelectedFacility.Instances.Remove(instance);
|
||
}
|
||
}
|
||
[RelayCommand]
|
||
private void SelectSelectedInstances(IList list)
|
||
{
|
||
if (list != null && list.Count > 0)
|
||
{
|
||
var candidates = new HashSet<FamilyInstance>(
|
||
list.Cast<object>().Where(x => x is FamilyInstance).Cast<FamilyInstance>());
|
||
var uidoc = GlobalVariables.UIApplication.ActiveUIDocument;
|
||
uidoc.Selection.SetElementIds(new HashSet<ElementId>(candidates.Select(i => i.Id)));
|
||
}
|
||
}
|
||
[RelayCommand]
|
||
private void SelectAllInstances()
|
||
{
|
||
if (SelectedFacility?.Instances.Count > 0)
|
||
{
|
||
var uidoc = GlobalVariables.UIApplication.ActiveUIDocument;
|
||
uidoc.Selection.SetElementIds(new HashSet<ElementId>(SelectedFacility.Instances
|
||
.Select(i => i.Id)));
|
||
}
|
||
}
|
||
[RelayCommand]
|
||
private void RemoveAllInstances()
|
||
{
|
||
SelectedFacility?.Instances.Clear();
|
||
}
|
||
[RelayCommand]
|
||
private void RepickSamplingInstances(Family family)
|
||
{
|
||
if (family == null || !family.IsValidObject)
|
||
{
|
||
return;
|
||
}
|
||
var uidoc = GlobalVariables.UIApplication.ActiveUIDocument;
|
||
try
|
||
{
|
||
while (true)
|
||
{
|
||
var excludedIds = new HashSet<int>(SelectedFacility.Instances.Select(i => i.Id.IntegerValue));
|
||
|
||
var reference = uidoc.Selection
|
||
.PickObject(
|
||
Autodesk.Revit.UI.Selection.ObjectType.Element,
|
||
new FuncFilter(
|
||
e => e is FamilyInstance fi &&
|
||
fi.Symbol.Family.Id.IntegerValue == family.Id.IntegerValue &&
|
||
!excludedIds.Contains(e.Id.IntegerValue)),
|
||
"请选择关联的族实例");
|
||
var instance = uidoc.Document.GetElement(reference) as FamilyInstance;
|
||
SelectedFacility?.Instances.Add(instance);
|
||
}
|
||
}
|
||
catch (Autodesk.Revit.Exceptions.OperationCanceledException)
|
||
{
|
||
}
|
||
}
|
||
[RelayCommand]
|
||
private void RepickInstancesByRectangle(Family family)
|
||
{
|
||
if (family == null || !family.IsValidObject)
|
||
{
|
||
return;
|
||
}
|
||
var uidoc = GlobalVariables.UIApplication.ActiveUIDocument;
|
||
try
|
||
{
|
||
var excludedIds = new HashSet<int>(SelectedFacility.Instances.Select(i => i.Id.IntegerValue));
|
||
var instances = uidoc.Selection
|
||
.PickElementsByRectangle(
|
||
new FuncFilter(
|
||
e => e is FamilyInstance fi &&
|
||
fi.Symbol.Family.Id.IntegerValue == family.Id.IntegerValue
|
||
&& !excludedIds.Contains(e.Id.IntegerValue)),
|
||
"请选择关联的族实例").Cast<FamilyInstance>();
|
||
foreach (var item in instances)
|
||
{
|
||
SelectedFacility?.Instances.Add(item);
|
||
}
|
||
|
||
}
|
||
catch (Autodesk.Revit.Exceptions.OperationCanceledException)
|
||
{
|
||
}
|
||
}
|
||
|
||
~FacilityInfoProcessViewModel()
|
||
{
|
||
if (GlobalVariables.UIApplication.IsValidObject)
|
||
{
|
||
GlobalVariables.UIApplication.ViewActivated -= UIApplication_ViewActivated;
|
||
}
|
||
}
|
||
}
|
||
|
||
public partial class ParameterItem : ObservableObject
|
||
{
|
||
public ParameterItem(string name, string value = "")
|
||
{
|
||
Name = name;
|
||
Value = value;
|
||
}
|
||
public ParameterItem()
|
||
{
|
||
|
||
}
|
||
[ObservableProperty]
|
||
public partial string Name { get; set; }
|
||
[ObservableProperty]
|
||
public partial string Value { get; set; }
|
||
}
|
||
/// <summary>
|
||
/// Excel表里的设备项
|
||
/// </summary>
|
||
public partial class FacilityItem : ObservableObject
|
||
{
|
||
public FacilityItem()
|
||
{
|
||
if (!string.IsNullOrEmpty(ParameterString))
|
||
{
|
||
Parameters = ProcessParameters(ParameterString);
|
||
}
|
||
}
|
||
|
||
[ObservableProperty]
|
||
public partial bool IsSelected { get; set; }
|
||
[ExcelTableColumn("设备")]
|
||
public string Name { get; set; }
|
||
|
||
[ExcelTableColumn("部署范围")]
|
||
public string Stations { get; set; }
|
||
[ExcelTableColumn("设备参数")]
|
||
[ObservableProperty]
|
||
public partial string ParameterString { get; set; }
|
||
partial void OnParameterStringChanged(string value)
|
||
{
|
||
if (!string.IsNullOrEmpty(value))
|
||
{
|
||
Parameters = ProcessParameters(value);
|
||
}
|
||
}
|
||
[ObservableProperty]
|
||
public partial string SearchText { get; set; }
|
||
|
||
public ICollectionView CollectionView { get; private set; }
|
||
public ObservableCollection<FamilyInstance> Instances { get; set; } = [];
|
||
public string Brand { get; set; }
|
||
public string Specification { get; set; }
|
||
|
||
[ObservableProperty]
|
||
[NotifyPropertyChangedFor(nameof(DisplayText))]
|
||
public partial Family MappedFamily { get; set; } = null;
|
||
|
||
|
||
partial void OnMappedFamilyChanged(Family value)
|
||
{
|
||
var doc = value.Document;
|
||
Instances.Clear();
|
||
List<FamilyInstance> instances = [..doc.ActiveView.QueryInstancesByType<FamilyInstance>()
|
||
.Cast<FamilyInstance>()
|
||
.Where(fi => fi.Symbol.Family.Id.IntegerValue == value.Id.IntegerValue)];
|
||
foreach (var instance in instances)
|
||
{
|
||
Instances.Add(instance);
|
||
}
|
||
CollectionView = CollectionViewSource.GetDefaultView(Instances);
|
||
|
||
CollectionView.Filter = o =>
|
||
{
|
||
if (string.IsNullOrEmpty(SearchText))
|
||
return true;
|
||
if (o is FamilyInstance ins)
|
||
{
|
||
//var title = GlobalVariables.UIApplication.ActiveUIDocument.Document.Title;
|
||
//var match = Regex.Match(title, @"(?<=^\d+号线-)([^-]+?)(?=车辆段|站|区间|停车场|主变电|变电所)");
|
||
//string result = match.Success ? match.Value : string.Empty;
|
||
return ins.Name.Contains(SearchText);
|
||
}
|
||
return false;
|
||
};
|
||
}
|
||
|
||
public string DisplayText => MappedFamily switch
|
||
{
|
||
null => "未匹配",
|
||
_ => $"{MappedFamily?.Name ?? "未命名族"}"
|
||
};
|
||
[ObservableProperty]
|
||
public partial string ErrorMessage { get; set; }
|
||
|
||
[ObservableProperty]
|
||
public partial List<ParameterItem> Parameters { get; set; }
|
||
|
||
private List<ParameterItem> ProcessParameters(string input)
|
||
{
|
||
List<ParameterItem> parameters = [];
|
||
|
||
//string pattern = @"^([^:]+):(.*)$";
|
||
string pattern = @"^([^::]+)[::](.*)$";
|
||
MatchCollection matches = Regex.Matches(input, pattern, RegexOptions.Multiline);
|
||
foreach (Match match in matches)
|
||
{
|
||
// Group[1] 是冒号前的内容 (参数名)
|
||
string paramName = match.Groups[1].Value.Trim();
|
||
if (string.IsNullOrEmpty(paramName))
|
||
{
|
||
continue;
|
||
}
|
||
string paramValue = match.Groups[2].Value;
|
||
if (string.IsNullOrEmpty(paramValue))
|
||
{
|
||
continue;
|
||
}
|
||
if (paramName == "品牌")
|
||
{
|
||
Brand = paramValue;
|
||
}
|
||
if (paramName == "设备型号")
|
||
{
|
||
Specification = paramValue;
|
||
}
|
||
// Group[2] 是冒号后的所有内容 (参数值)
|
||
var parameterItem = new ParameterItem
|
||
{
|
||
Name = paramName,
|
||
Value = paramValue
|
||
};
|
||
var isExist = parameters.Any(p => p.Name == paramName);
|
||
if (isExist)
|
||
{
|
||
ErrorMessage += $"{paramName}参数名重复\n";
|
||
}
|
||
else
|
||
{
|
||
parameters.Add(parameterItem);
|
||
}
|
||
}
|
||
return parameters;
|
||
}
|
||
public override string ToString()
|
||
{
|
||
return $"{Name} {Brand} {Specification} {Stations}";
|
||
}
|
||
}
|
||
} |