Files
ShrlAlgoToolkit/ShrlAlgoToolkit.RevitAddins/FamMaster/FamilyLibraryViewModel.cs
2026-03-01 10:42:42 +08:00

470 lines
14 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Collections.ObjectModel;
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 ShrlAlgoToolkit.RevitAddins.Common.Assists;
using static ShrlAlgoToolkit.RevitCore.Assists.RevitFileAssist;
using Settings = ShrlAlgoToolkit.RevitAddins.Properties.Settings;
using ShrlAlgoToolkit.RevitAddins.RvFamily.FamilyLibrary;
namespace ShrlAlgoToolkit.RevitAddins.FamMaster;
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]
public partial string FamilyPath { get; set; }
[ObservableProperty]
public partial int PageCount { get; set; }
[ObservableProperty]
public partial int PageSize { get; set; }
[ObservableProperty]
public partial string RevitVersion { get; set; }
[ObservableProperty]
public partial FamilyModel SelectedFamily { get; set; }
[ObservableProperty]
public partial FamilyTypeDefinition SelectedSymbolType { get; set; }
[ObservableProperty]
public partial List<FamilyTypeDefinition> SymbolTypes { get; set; }
[ObservableProperty]
public partial bool ActiveSnackbar { get; set; }
[ObservableProperty]
public partial Melskin.Controls.Alert MessageQueue { get; set; } = new();
[ObservableProperty]
public partial string Message { get; set; }
partial void OnMessageChanged(string value)
{
ActiveSnackbar = true;
}
public int FamilyCount => FamilyDataSource.Count;
/// <summary>
/// 选择树路径时的源
/// </summary>
public ObservableCollection<FamilyModel> FamilyDataSource { get; } = new();
/// <summary>
/// 单页显示的源
/// </summary>
public ObservableCollection<FamilyModel> FamilyPageListViewItems { get; set; } = new();
public ObservableCollection<TreeViewItem> 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;
/// <summary>
/// 加载目录树节点的初始化数据
/// </summary>
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;
}
/// <summary>
/// 懒加载
/// </summary>
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;
}
/// <summary>
/// 递归获取路径下的所有族文件
/// </summary>
/// <param name="fullPath"></param>
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);
}
}
/// <summary>
/// 将族加载到当前文件中
/// </summary>
[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)
{
if (obj is FamilyModel familyInfo)
{
WinDialogAssist.OpenFolderAndSelectFile(familyInfo.Path);
}
}
[RelayCommand]
private void LvSelectionChanged(object obj)
{
if (obj is FamilyModel familyInfo)
{
var assist = new RevitFileAssist(familyInfo.Path);
SymbolTypes = assist.SymbolTypes;
SelectedSymbolType = SymbolTypes.FirstOrDefault();
RevitVersion = assist.RevitVersion;
}
}
/// <summary>
/// 绑定TreeView数据源.
/// </summary>
/// <param name="path">The Path<see cref="string" />.</param>
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 };
/* 项目“ShrlAlgoToolkit.RevitAddins (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.Tip, false, 0, true);
//if (foundItem != null)
//{
// textListView.TopItem = foundItem;
//}
//Func<string, bool> searchFunc = BreakCurve;
//Task<bool> task = new Task<bool>(() => 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()))
//{
//}
}
}
}
/// <summary>
/// 选择树状节点
/// </summary>
/// <param name="obj"></param>
[RelayCommand]
private void SelectDirTreeNode(object obj)
{
//e.OriginalSource 就是TreeViewItem对象你可以将其保存到窗体类的某个私有字段中或者直接使用它如下所示
FamilyDataSource.Clear();
if (obj is TreeViewItem selectedItem)
{
GetFamilyFile(selectedItem.Tag.ToString());
}
LoadInitialData();
SymbolTypes = null;
}
/// <summary>
/// 路径选择.
/// </summary>
[RelayCommand]
private void SelectPath()
{
var dialog = new Melskin.Controls.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);
}
}
}
/// <summary>
/// 递归添加目录结构到TreeView根节点.
/// </summary>
/// <param name="subDirs">.</param>
/// <param name="nodeToAddTo">根节点.</param>
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)
{
/* 项目“ShrlAlgoToolkit.RevitAddins (net481)”的未合并的更改
在此之前:
SubDirectories(subSubDirs, aNode);
在此之后:
FamilyLibraryViewModel.SubDirectories(subSubDirs, aNode);
*/
SubDirectories(subSubDirs, aNode);
}
nodeToAddTo.Items.Add(aNode);
}
}
}