using System.Collections.ObjectModel; using System.Diagnostics; using System.IO; using System.Windows; using System.Windows.Controls; using Autodesk.Revit.DB; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using FuzzySharp; using Nice3point.Revit.Toolkit.External.Handlers; using Wpf.Ui.Extend.Controls; using Settings = Sai.RvKits.Properties.Settings; namespace Sai.RvKits.RvFamily.FamilyLibrary; public partial class FamilyLibraryViewModel : ObservableObject { public FamilyLibraryViewModel() { loadFamilyHandler = new ActionEventHandler(); loadFamilySymbolHandler = new ActionEventHandler(); #if REVIT2018 familyPath = Settings.Default.FamilyPath_2018; #elif REVIT2019 familyPath = Settings.Default.FamilyPath_2019; #elif REVIT2020 familyPath = Settings.Default.FamilyPath_2020; #elif REVIT2021 familyPath = Settings.Default.FamilyPath_2021; #endif PageSize = 20; Initialize(); } private readonly ActionEventHandler loadFamilyHandler; private readonly ActionEventHandler loadFamilySymbolHandler; [ObservableProperty] private string familyPath; [ObservableProperty] private int pageCount; [ObservableProperty] private int pageSize; [ObservableProperty] private string revitVersion; [ObservableProperty] private FamilyModel selectedFamily; [ObservableProperty] private FamilySymbolType selectedSymbolType; [ObservableProperty] private List symbolTypes; [ObservableProperty] private bool activeSnackbar; [ObservableProperty] private Wpf.Ui.Controls.InfoBar messageQueue = new(); [ObservableProperty] private string message; partial void OnMessageChanged(string value) { ActiveSnackbar = true; } public int FamilyCount => FamilyDataSource.Count; /// /// 选择树路径时的源 /// public ObservableCollection FamilyDataSource { get; } = new(); /// /// 单页显示的源 /// public ObservableCollection FamilyPageListViewItems { get; set; } = new(); public ObservableCollection FolderTreeViewItems { get; set; } = new(); [RelayCommand] private void LvScroll(ScrollViewer scrollViewer) { // ReSharper disable once CompareOfFloatsByEqualityOperator if (!isLoadingData && scrollViewer.VerticalOffset + scrollViewer.ViewportHeight == scrollViewer.ExtentHeight) { LoadMoreData(); } } private const int BatchSize = 10; private bool isLoadingData; /// /// 加载目录树节点的初始化数据 /// private void LoadInitialData() { isLoadingData = true; FamilyPageListViewItems.Clear(); var size = BatchSize; if (FamilyDataSource.Count < BatchSize) { size = FamilyDataSource.Count; } for (var i = 0; i < size; i++) { FamilyPageListViewItems.Add(FamilyDataSource[i]); } isLoadingData = false; } /// /// 懒加载 /// private void LoadMoreData() { isLoadingData = true; var startIndex = FamilyPageListViewItems.Count; var end = startIndex + BatchSize; if (end > FamilyDataSource.Count) { end = FamilyDataSource.Count; } if (startIndex < end + 1) { for (var i = startIndex; i < end; i++) { FamilyPageListViewItems.Add(FamilyDataSource[i]); } } isLoadingData = false; } /// /// 递归获取路径下的所有族文件 /// /// private void GetFamilyFile(string fullPath) { DirectoryInfo dir = new(fullPath); try { if (!dir.Exists) { return; } //文件系统,包含文件夹和文件 var files = dir.GetFileSystemInfos(); foreach (var fSys in files) { //FSys如果是文件则fileinfo不为空 if (fSys is FileInfo fileInfo) { if (fileInfo.Extension == ".rfa") { var sfInfo = new FileInfo(fileInfo.DirectoryName + "\\" + fileInfo.Name); //RevitFileUtil.ParserRevitFile(sfInfo.FullName); var model = new FamilyModel { FileInfo = sfInfo, Path = sfInfo.FullName, Title = Path.GetFileNameWithoutExtension(sfInfo.FullName), ToolTip = sfInfo.Name //RevitVersion = RevitFileUtil.RevitVersion }; FamilyDataSource.Add(model); } } else //当fileinfo为空,即为文件夹,向下查找 { GetFamilyFile($"{fullPath}\\{fSys}"); } } } catch (Exception ex) { MessageBox.Show(ex.Message); } } /// /// 将族加载到当前文件中 /// [RelayCommand] private void ImportFamily(FamilyModel model) { //将model的绑定数据传给外部事件 loadFamilyHandler.Raise(app => { try { var doc = app.ActiveUIDocument.Document; Family family; FamilySymbol fs = null; doc.Invoke( _ => { family = doc.GetOrLoadedFamily(model.Path); fs = doc.GetElement(family.GetFamilySymbolIds().FirstOrDefault()) as FamilySymbol; //if (fs != null && !fs.IsActive) //{ // fs.Activate(); //} //if (family == null) //{ // doc.LoadFamily(FileLibModel.Path, familyLoadOption, out family); // fs = doc.GetElement(family.GetFamilySymbolIds().FirstOrDefault()) as FamilySymbol; // //} //else //{ // MessageBox.ShowAhead("族已载入或载入失败。", "提示"); //} }, "载入族-" + Path.GetFileNameWithoutExtension(model.Path) ); if (fs != null && app.ActiveUIDocument.CanPlaceElementType(fs)) { app.ActiveUIDocument.PromptForFamilyInstancePlacement(fs); } } catch (Autodesk.Revit.Exceptions.OperationCanceledException) { } catch (Exception e) { Message = e.Message; e.Message.ToLog(); } }); } [RelayCommand] private void ImportFamilySymbol() { if (SelectedFamily == null || SelectedSymbolType == null) { return; } loadFamilySymbolHandler.Raise(app => { var uidoc = app.ActiveUIDocument; var doc = uidoc.Document; //当前选择的族类型 FamilySymbol fs = null; if (SelectedSymbolType.Name == null) { return; } doc.Invoke( _ => { var fam = doc.GetOrLoadedFamily(SelectedFamily.Path); doc.Regenerate(); //if (fam == null) //{ // doc.LoadFamilySymbol(FamilyPath, FamilySymbolName, out fs); //} //else //{ var x = fam.GetFamilySymbolIds() .FirstOrDefault(id => doc.GetElement(id).Name == SelectedSymbolType.Name); fs = doc.GetElement(x) as FamilySymbol; //} if (fs?.IsActive == false) { fs.Activate(); } }, "载入族-" + Path.GetFileNameWithoutExtension(SelectedFamily.Path) + " 类型:" + SelectedSymbolType.Name ); try { if (fs != null && uidoc.CanPlaceElementType(fs)) { app.ActiveUIDocument.PromptForFamilyInstancePlacement(fs); } } catch (Autodesk.Revit.Exceptions.OperationCanceledException) { } catch (Exception e) { e.Message.ToLog(); } }); } private void Initialize() { PopulateTreeView(FamilyPath); GetFamilyFile(FamilyPath); //CurrentPageIndex = 0; LoadInitialData(); //PageCount = GetPageCount(); //PageOrderNumberCollection = GetOrderIntCollection(); //CollectionViewSource.GetDefaultView(FamilyPageListViewItems); } [RelayCommand] private static void LocationFamilyFile(object obj) { //System.Windows.Controls.Button btn = obj as System.Windows.Controls.Button; if (obj is FamilyModel familyInfo) { var proc = new System.Diagnostics.Process(); proc.StartInfo.FileName = "explorer"; //打开资源管理器 proc.StartInfo.Arguments = "/select," + familyInfo.Path; proc.Start(); } } [RelayCommand] private void LvSelectionChanged(object obj) { if (obj is FamilyModel familyInfo) { RevitFileUtil.ParserRevitFile(familyInfo.Path); SymbolTypes = RevitFileUtil.SymbolTypes; SelectedSymbolType = SymbolTypes.FirstOrDefault(); RevitVersion = RevitFileUtil.RevitVersion; } } /// /// 绑定TreeView数据源. /// /// The Path. private void PopulateTreeView(string path) { FolderTreeViewItems?.Clear(); var info = new DirectoryInfo(path); if (!info.Exists) { return; } var rootNode = new TreeViewItem { Header = info.Name, Tag = info.FullName }; /* 项目“Sai.RvKits (net481)”的未合并的更改 在此之前: SubDirectories(info.GetDirectories(), rootNode); 在此之后: FamilyLibraryViewModel.SubDirectories(info.GetDirectories(), rootNode); */ SubDirectories(info.GetDirectories(), rootNode); //dirTree.DataContext = rootNode; FolderTreeViewItems!.Add(rootNode); rootNode.IsExpanded = true; } [RelayCommand] private void SearchFamily(object obj) { //ListViewItem foundItem = // textListView.FindItemWithText(searchBox.Text, false, 0, true); //if (foundItem != null) //{ // textListView.TopItem = foundItem; //} //Func searchFunc = BreakCurve; //Task task = new Task(() => BreakCurve(obj.ToString())); //task.Start(); //await task; if (string.IsNullOrEmpty(obj.ToString())) { LoadInitialData(); //FamilyPageListViewItems.Clear(); //itemsLoaded.ForEach(item => FamilyPageListViewItems.Add(item)); } else { //itemsLoaded.Clear(); //FamilyPageListViewItems.ForEach(item => itemsLoaded.Add(item)); FamilyPageListViewItems.Clear(); foreach (var item in FamilyDataSource) { if (Fuzz.PartialRatio(item.Title,obj.ToString())>70) { FamilyPageListViewItems.Add(item); } //if (item.Title.Contains(obj.ToString())) //{ //} } } } /// /// 选择树状节点 /// /// [RelayCommand] private void SelectDirTreeNode(object obj) { //e.OriginalSource 就是TreeViewItem对象,你可以将其保存到窗体类的某个私有字段中,或者直接使用它,如下所示: FamilyDataSource.Clear(); if (obj is TreeViewItem selectedItem) { GetFamilyFile(selectedItem.Tag.ToString()); } LoadInitialData(); SymbolTypes = null; } /// /// 路径选择. /// [RelayCommand] private void SelectPath() { var dialog = new VistaFolderBrowserDialog(); if (dialog.ShowDialog() == true) { try { #if REVIT2018 Settings.Default.FamilyPath_2018 = dialog.SelectedPath; #elif REVIT2019 Settings.Default.FamilyPath_2019 = dialog.SelectedPath; #elif REVIT2020 Settings.Default.FamilyPath_2020 = dialog.SelectedPath; #elif REVIT2021 Settings.Default.FamilyPath_2021 = dialog.SelectedPath; #endif PopulateTreeView(dialog.SelectedPath); } catch (Exception ex) { MessageBox.Show(ex.Message); } } } /// /// 递归添加目录结构到TreeView根节点. /// /// . /// 根节点. private static void SubDirectories(DirectoryInfo[] subDirs, TreeViewItem nodeToAddTo) { //父节点 foreach (var subDir in subDirs) { var aNode = new TreeViewItem { Header = subDir.Name, Tag = subDir.FullName }; //获取子目录 var subSubDirs = subDir.GetDirectories(); if (subSubDirs.Length != 0) { /* 项目“Sai.RvKits (net481)”的未合并的更改 在此之前: SubDirectories(subSubDirs, aNode); 在此之后: FamilyLibraryViewModel.SubDirectories(subSubDirs, aNode); */ SubDirectories(subSubDirs, aNode); } nodeToAddTo.Items.Add(aNode); } } }