using System.Collections.ObjectModel; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using Autodesk.Revit.DB; using Autodesk.Revit.DB.Architecture; using Autodesk.Revit.UI; using ColorHelper; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using Nice3point.Revit.Toolkit.External.Handlers; namespace Szmedi.RvKits.ModelManager { public partial class LevelSeparateViewModel : ObservableObject { private ActionEventHandler handler = new(); //[ObservableProperty] //private bool toFillLevelName; private readonly UIDocument uidoc; //private readonly ProcessEventHandler> process; [ObservableProperty] private string projectName; [ObservableProperty] private bool toFillColor; public LevelSeparateViewModel(UIDocument uidoc) { ProjectName = uidoc.Document.Title.Replace(".rvt", string.Empty); this.uidoc = uidoc; //process = new ProcessEventHandler>( // async (uiapp, dict, obj) => // { // var color = new Color(dict.Value.Color.R, dict.Value.Color.G, dict.Value.Color.B); // if (ToFillLevelName) // { // var param = dict.Key.GetParameters("所属楼层").FirstOrDefault(); // if (param != null && !param.IsReadOnly) // { // param.Set(dict.Value.LevelName); // } // } // if (ToFillColor) // { // dict.Key.SetFillColor(color); // } // await Task.Delay(10); // }); } public bool? IsAllItemsSelected { get { var isVisible = Items?.Select(item => item.IsVisible).Distinct().ToList(); return isVisible == null ? false : isVisible.Count() == 1 ? isVisible.Single() : null; } set { if (value.HasValue) { SelectAll(value.Value, Items); OnPropertyChanged(); } } } public ObservableCollection Items { get; set; } = []; private static void SelectAll(bool isVisible, IEnumerable models) { foreach (var item in models) { item.IsVisible = isVisible; } } [RelayCommand] private void ExportToCsv(LevelItem item) { FolderBrowserDialog browserWindow = new(); if (browserWindow.ShowDialog()) { var selectedPath = browserWindow.SelectedPath; if (!Directory.Exists(selectedPath)) { MessageBox.Show("文件目录不存在!", "警告"); return; } var path = Path.Combine(selectedPath, $"{ProjectName}-{item.LevelName}-{DateTime.Now:yyyy-mm-dd-HH-mm}.csv"); var sb = new StringBuilder(); sb.AppendLine("元素Id,族,类型,"); foreach (var instance in item.Elements) { var elem = uidoc.Document.GetElement(instance.GetTypeId()); var familyName = elem switch { ElementType elementType => elementType.FamilyName, null => instance.Name, _ => elem.Name }; sb.AppendLine($"{instance.Id},{familyName},{instance.Name},"); } File.WriteAllText(path, sb.ToString(), Encoding.UTF8); var result = MessageBox.Show( "是否打开导出的文件", "导出完成", MessageBoxButton.OKCancel, MessageBoxImage.Information); if (result == MessageBoxResult.OK) { Process.Start(path); } } } /// /// 楼层划分 /// [RelayCommand] private async Task GroupByLevel() { await Task.Delay(300); var result = MessageBox.Show("此操作会覆盖已经设置所属楼层的构件参数,是否知晓并继续?", "提示", MessageBoxButton.YesNo, MessageBoxImage.Question); if (result == MessageBoxResult.No) { return; } Items.Clear(); var unknownLevel = new LevelItem(handler) { LevelName = "{未知楼层}", LevelId = ElementId.InvalidElementId, Elements = [], Color = ColorName.Red.ToRgb() }; var doc = uidoc.Document; var levelOutlines = doc.GetLevelRanges(); var n = 1; //对比标高,得到实际分层位置 var allModels = doc.OfAllModelCollector(); if (allModels == null) { MessageBox.Show("没有找到模型元素", "错误"); return; } Debug.WriteLine($"模型总数:{allModels.Count()}"); foreach (var keyPair in levelOutlines) { //Debug.WriteLine($"---------------------"); BoundingBoxIsInsideFilter insideFilter = new(keyPair.Value); //所有模型中得到在标高范围内的元素 //除了墙、梁、板、柱、楼梯 var insideList = doc.OfAllModelCollector() .WherePasses(insideFilter) .Where( e => e is not (Stairs or Wall) && e.Category.ToBuiltInCategory() is not (BuiltInCategory.OST_StructuralFraming or BuiltInCategory.OST_Floors or BuiltInCategory.OST_StructuralColumns or BuiltInCategory.OST_Columns)); var level = keyPair.Key; //Debug.WriteLine($"{level.Name}上的范围元素:{insideList.Count()}"); //var ids = insideList.Where(dict => dict.get_BoundingBox(null) != null); LevelItem item = new(handler) { LevelName = level.Name, LevelId = level.Id, Elements = new ObservableCollection(insideList), Color = ((ColorName)n).ToRgb() }; var ids = insideList.Select(e => e.Id); //排除范围内的元素 if (ids.Any()) { allModels.Excluding(ids.ToList()); } Items.Add(item); //Debug.WriteLine($"{level.Name}上合计构件数:{item.Elements.Count}"); n++; } foreach (var item in Items) { //所有模型中通过模型自身的主体、参照获取标高,墙、梁、板、柱、楼梯 var checkedList = new List(); foreach (var model in allModels) { var modelLevelId = model.GetLevelId(); if (modelLevelId == item.LevelId) { item.Elements.Add(model); checkedList.Add(model.Id); } else { if (model is FamilyInstance ins && ins.Host != null) { var hostLevel = ins.Host.GetLevelId(); if (item.LevelId == hostLevel) { item.Elements.Add(model); checkedList.Add(model.Id); } } if (model is Railing railing && railing.HasHost) { var host = doc.GetElement(railing.HostId); var hostLevel = host.GetLevelId(); if (item.LevelId == hostLevel) { item.Elements.Add(model); checkedList.Add(model.Id); } } } } Debug.WriteLine($"{item.LevelName}上的特殊构件:{checkedList.Count}"); if (checkedList.Any()) { allModels.Excluding(checkedList); } } //存在未知标高的构件时 if (allModels.Any()) { unknownLevel.Elements = new ObservableCollection(allModels); Items.Add(unknownLevel); } if (ToFillColor) { handler.Raise( uiapp => { uiapp.ActiveUIDocument.Document .Invoke( ts => { foreach (var item in Items) { var color = new Color(item.Color.R, item.Color.G, item.Color.B); foreach (var elem in item.Elements) { elem.SetFillColor(color); } } }, "填充颜色"); }); } //Export(); //if (ToFillLevelName || ToFillColor) //{ // var manager = new ProgressBarManager>(process, dict); // manager.ProgressModeless(); //} } private void Export() { var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), $"{ProjectName}-{DateTime.Now:yyyy-mm-dd-HH-mm}.csv"); var sb = new StringBuilder(); sb.AppendLine("楼层,元素Id,族,类型,"); foreach (var item in Items) { foreach (var instance in item.Elements) { var elem = uidoc.Document.GetElement(instance.GetTypeId()); var familyName = elem switch { ElementType elementType => elementType.FamilyName, null => instance.Name, _ => elem.Name }; sb.AppendLine($"{item.LevelName},{instance.Id},{familyName},{instance.Name},"); } } File.WriteAllText(path, sb.ToString(), Encoding.UTF8); } /// /// 楼层划分 /// //[RelayCommand] //private void GroupByLevelBackup() //{ // Items.Clear(); // handler.Raise( // uiapp => // { // var unknownLevel = new LevelItem(handler) // { // LevelName = "<未知楼层>", // LevelId = ElementId.InvalidElementId, // Count = 0, // Elements = [], // Color = ColorName.Red.ToRgb(), // }; // var doc = uiapp.ActiveUIDocument.Document; // var levelOutlines = doc.GetLevelRanges(); // doc.Invoke( // ts => // { // var n = 1; // //对比标高,得到实际分层位置 // var allModels = doc.OfModelCollector(); // foreach (var keyPair in levelOutlines) // { // BoundingBoxIsInsideFilter insideFilter = new(keyPair.Value); // //所有模型中得到在标高范围内的元素 // //除了墙、梁、板、柱、楼梯 // var insideList = doc.OfModelCollector() // .WherePasses(insideFilter) // .Where( // e => e is not (Stairs or Wall) && // e.Category.ToBuiltInCategory() is not (BuiltInCategory.OST_StructuralFraming // or BuiltInCategory.OST_Floors // or BuiltInCategory.OST_StructuralColumns // or BuiltInCategory.OST_Columns)); // var level = keyPair.Key; // //var ids = insideList.Where(dict => dict.get_BoundingBox(null) != null); // LevelItem level = new(handler) // { // LevelName = level.Name, // LevelId = level.Id, // Count = insideList.Count(), // Elements = new ObservableCollection(insideList), // Color = ((ColorHelper.ColorName)n).ToRgb(), // }; // var ids = insideList.Select(e => e.Id); // //排除范围内的元素 // if (ids.Any()) // { // allModels.Excluding(ids.ToList()); // } // //所有模型中通过模型自身的主体、参照获取标高,墙、梁、板、柱、楼梯 // var checkedList = new List(); // foreach (var level in allModels) // { // var modelLevelId = level.GetLevelId(); // if (modelLevelId == level.LevelId) // { // level.Elements.Add(level); // checkedList.Add(level.Id); // } // else // { // if (level is FamilyInstance roof && roof.Host != null) // { // var hostLevel = roof.Host.GetLevelId(); // if (level.LevelId == hostLevel) // { // level.Elements.Add(level); // checkedList.Add(level.Id); // } // } // if (level is Railing railing && railing.HasHost) // { // var host = doc.GetElement(railing.HostId); // var hostLevel = host.GetLevelId(); // if (level.LevelId == hostLevel) // { // level.Elements.Add(level); // checkedList.Add(level.Id); // } // } // } // } // try // { // if (checkedList.Any()) // { // allModels.Excluding(checkedList); // } // } // catch (Exception) // { // throw; // } // level.Count = level.Elements.Count; // Items.Add(level); // if (ToFillLevelName || ToFillColor) // { // doc.InvokeSub( // sub => // { // var color = new Color(level.Color.R, level.Color.G, level.Color.B); // foreach (var dict in level.Elements) // { // if (ToFillLevelName) // { // dict.GetParameters("所属楼层").FirstOrDefault()?.Set(level.LevelName); // } // if (ToFillColor) // { // dict.SetFillColor(color); // } // } // }); // } // n++; // } // //存在未知标高的构件时 // if (allModels.Any()) // { // unknownLevel.Elements = new ObservableCollection(allModels); // unknownLevel.Count = unknownLevel.Elements.Count; // Items.Add(unknownLevel); // } // }, // "根据楼层划分"); // }); //} [RelayCommand] private void ReadCurrentModel() { //await Task.Delay(300); Items.Clear(); var allModels = uidoc.Document .OfAllModelCollector(); if (allModels == null) { MessageBox.Show("当前项目中没有模型!", "提示"); return; } Debug.WriteLine($"模型总数:{allModels?.Count()}"); var instances = allModels.ToList() .Where(e => e is FamilyInstance ins && ins.GetSubComponentIds().Count > 0) .Cast().ToList(); var curtainWalls = allModels.ToList().Where(e => e is Wall wall && wall.CurtainGrid != null).Cast().ToList(); var curtainRoofs = allModels.ToList().Where(e => e is FootPrintRoof roof && roof.CurtainGrids != null) .Cast().ToList(); var stairs = allModels.ToList().Where(e => e is Stairs).Cast().ToList(); var railings = allModels.ToList().Where(e => e is Railing).Cast().ToList(); //var railings = allModels.ToList().Where(e => e is Railing).Cast(); handler.Raise( uiapp => { var doc = uiapp.ActiveUIDocument.Document; doc.Invoke( ts => { //共享嵌套族处理 foreach (var ins in instances) { var param = ins.GetParameters("所属楼层").FirstOrDefault(); var value = string.Empty; if (param != null && !param.IsReadOnly) { value = param.AsString(); } foreach (var id in ins.GetSubComponentIds()) { var sub = doc.GetElement(id); var p = sub.GetParameters("所属楼层").FirstOrDefault(); if (p != null && !p.IsReadOnly) { p.Set(value); } } } foreach (var roof in curtainRoofs) { var param = roof.GetParameters("所属楼层").FirstOrDefault(); var value = string.Empty; if (param != null && !param.IsReadOnly) { value = param.AsString(); } foreach (CurtainGrid grid in roof.CurtainGrids) { foreach (var id in grid.GetMullionIds()) { var sub = doc.GetElement(id); var p = sub.GetParameters("所属楼层").FirstOrDefault(); if (p != null && !p.IsReadOnly) { p.Set(value); } } foreach (var id in grid.GetPanelIds()) { var sub = doc.GetElement(id); var p = sub.GetParameters("所属楼层").FirstOrDefault(); if (p != null && !p.IsReadOnly) { p.Set(value); } } } } //幕墙子类别处理 foreach (var wall in curtainWalls) { var param = wall.GetParameters("所属楼层").FirstOrDefault(); var value = string.Empty; if (param != null && !param.IsReadOnly) { value = param.AsString(); } foreach (var id in wall.CurtainGrid.GetMullionIds()) { var sub = doc.GetElement(id); var p = sub.GetParameters("所属楼层").FirstOrDefault(); if (p != null && !p.IsReadOnly) { p.Set(value); } } foreach (var id in wall.CurtainGrid.GetPanelIds()) { var sub = doc.GetElement(id); if (sub is Panel panel && panel.FindHostPanel() != ElementId.InvalidElementId) { var hostId = panel.FindHostPanel(); var host = doc.GetElement(hostId); var hostP = host.GetParameters("所属楼层").FirstOrDefault(); if (hostP != null && !hostP.IsReadOnly) { var b = hostP.Set(value); } } var p = sub.GetParameters("所属楼层").FirstOrDefault(); if (p != null && !p.IsReadOnly) { var b = p.Set(value); } } } foreach (var stair in stairs) { var runs = stair.GetStairsRuns(); var landings = stair.GetStairsLandings(); var supports = stair.GetStairsSupports(); var param = stair.GetParameters("所属楼层").FirstOrDefault(); var value = string.Empty; if (param != null && !param.IsReadOnly) { value = param.AsString(); } SetSubComponent(doc, runs, value); SetSubComponent(doc, landings, value); SetSubComponent(doc, supports, value); } foreach (var railing in railings) { var param = railing.GetParameters("所属楼层").FirstOrDefault(); var value = string.Empty; if (param != null && !param.IsReadOnly) { value = param.AsString(); } var topRailId = railing.TopRail; if (topRailId != ElementId.InvalidElementId) { var sub = doc.GetElement(topRailId); var p = sub.GetParameters("所属楼层").FirstOrDefault(); if (p != null && !p.IsReadOnly) { p.Set(value); } } } }, "更新子构件的所属楼层"); var groups = allModels.GroupBy(e => { var param = e.GetParameters("所属楼层").FirstOrDefault(); var value = param?.AsString(); if (string.IsNullOrEmpty(value)) { return null; } return param.AsString(); }); var n = 1; handler = new ActionEventHandler(); foreach (var group in groups) { //Debug.WriteLine($"{group.Key}模型数量:{group.Count()}"); //var instances = group.ToList(); LevelItem item = new(handler) { LevelName = group.Key ?? "{未知楼层}", Elements = [.. group], Color = ((ColorName)n).ToRgb() }; Items.Add(item); n++; } if (ToFillColor) { uiapp.ActiveUIDocument.Document .Invoke( ts => { foreach (var item in Items) { var color = new Color(item.Color.R, item.Color.G, item.Color.B); foreach (var elem in item.Elements) { elem.SetFillColor(color); } } }, "填充颜色"); } }); //Export(); } private static void SetSubComponent(Document doc, ICollection ids, string value) { foreach (var id in ids) { var sub = doc.GetElement(id); var p = sub.GetParameters("所属楼层").FirstOrDefault(); if (p != null && !p.IsReadOnly) { p.Set(value); } } } [RelayCommand] private void SetColorOverride(object obj) { handler.Raise( uiapp => { if (obj is LevelItem levelItem) { var doc = uiapp.ActiveUIDocument.Document; var color = new Color(levelItem.Color.R, levelItem.Color.G, levelItem.Color.B); doc.Invoke( ts => { foreach (var elem in levelItem.Elements) { elem.SetFillColor(color); } }, "填充颜色"); } }); } [RelayCommand] private void ResetColorOverride() { handler.Raise( uiapp => { var doc = uiapp.ActiveUIDocument.Document; doc.Invoke( ts => { OverrideGraphicSettings overrideGraphicSettings = new(); var elems = doc.OfAllModelCollector(); if (elems == null) { MessageBox.Show("没有找到模型元素", "错误"); return; } foreach (var elem in elems) { doc.ActiveView.SetElementOverrides(elem.Id, overrideGraphicSettings); doc.Regenerate(); } }, "重置外观"); }); } [RelayCommand] private void SelectElements(object obj) { if (obj is LevelItem item) { uidoc.Selection.SetElementIds(item.Elements.Select(e => e.Id).ToList()); } } } public partial class LevelItem : ObservableObject { private readonly ActionEventHandler handler; [ObservableProperty] private RGB color; [ObservableProperty] private bool isVisible = true; [ObservableProperty] private string levelName; public LevelItem(ActionEventHandler handler) { this.handler = handler; } public ObservableCollection Elements { get; set; } = []; public ElementId LevelId { get; set; } = ElementId.InvalidElementId; partial void OnIsVisibleChanged(bool oldValue, bool newValue) { if (oldValue != newValue) { handler.Raise( uiapp => { var doc = uiapp.ActiveUIDocument.Document; doc.Invoke( _ => { if (newValue) { doc.ActiveView .UnhideElements( Elements.Where(e => e.IsHidden(doc.ActiveView)).Select(e => e.Id).ToList()); } else { doc.ActiveView .HideElements( Elements.Where(e => e.CanBeHidden(doc.ActiveView)) .Select(e => e.Id) .ToList()); } }, $"显隐{LevelName}"); }); } } partial void OnLevelNameChanged(string oldValue, string newValue) { if (oldValue != newValue && newValue != "{未知楼层}") { handler.Raise( uiapp => { var doc = uiapp.ActiveUIDocument.Document; doc.Invoke( _ => { foreach (var elem in Elements) { var param = elem.GetParameters("所属楼层").FirstOrDefault(); if (param != null && !param.IsReadOnly) { param.Set(newValue); } } }, $"所属楼层{oldValue}->{newValue}"); }); } } } }