470 lines
14 KiB
C#
470 lines
14 KiB
C#
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);
|
||
}
|
||
}
|
||
}
|