优化更新代码,添加界面功能并整合

This commit is contained in:
GG Z
2025-02-10 20:53:40 +08:00
parent 83b846f15f
commit 978e03a67f
1389 changed files with 95739 additions and 22200 deletions

View File

@@ -0,0 +1,17 @@
using System.Windows;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.UI;
using Nice3point.Revit.Toolkit.External;
namespace ShrlAlgo.RvKits.RvFamily.FamilyLibrary;
[Transaction(TransactionMode.Manual)]
[Regeneration(RegenerationOption.Manual)]
public class FamilyLibraryCmd : ExternalCommand
{
public override void Execute()
{
WinDialogHelper.ShowModeless<FamilyLibraryView>(new FamilyLibraryViewModel());
}
}

View File

@@ -0,0 +1,315 @@
<ui:FluentWindowEx
x:Class="ShrlAlgo.RvKits.RvFamily.FamilyLibrary.FamilyLibraryView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:local="clr-namespace:ShrlAlgo.RvKits.RvFamily.FamilyLibrary"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="https://github.com/ShrlAlgo/WPFluent"
Title="本地族库"
Width="1050"
Height="600"
MinWidth="1050"
MinHeight="600"
d:DataContext="{d:DesignInstance Type=local:FamilyLibraryViewModel}"
ResizeMode="CanResizeWithGrip"
mc:Ignorable="d">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/ShrlAlgo.RvKits;component/WPFUI.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="220" />
</Grid.ColumnDefinitions>
<ui:Button
Grid.Row="0"
Margin="5"
HorizontalAlignment="Stretch"
Command="{Binding SelectPathCommand}"
Content="打开族目录"
FontFamily="{StaticResource BoxIcons}"
Icon="{ui:FontIcon Glyph=&#xEADF;,
FontFamily={StaticResource BoxIcons}}"
ToolTip="{Binding FamilyPath, Mode=OneWay, StringFormat=族目录:{}{0}}" />
<TreeView
x:Name="FolderTreeView"
Grid.Row="1"
d:ItemsSource="{d:SampleData}"
ItemsSource="{Binding FolderTreeViewItems}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectedItemChanged">
<i:InvokeCommandAction Command="{Binding SelectDirTreeNodeCommand}" CommandParameter="{Binding SelectedItem, RelativeSource={RelativeSource AncestorType={x:Type TreeView}, Mode=FindAncestor}}" />
<!--<behaviors:InvokeCommandAction Command="{Binding SetSelectedItem}" CommandParameter="{Binding SelectedItem, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=TreeView}}" />-->
</i:EventTrigger>
</i:Interaction.Triggers>
</TreeView>
<GridSplitter
Grid.Row="1"
Grid.Column="1"
Width="1"
HorizontalAlignment="Center"
ShowsPreview="True" />
<ui:TextBox
x:Name="SearchBox"
Grid.Row="0"
Grid.Column="2"
Margin="5"
Cursor="IBeam"
PlaceholderText="请输入搜索关键词">
<i:Interaction.Triggers>
<i:EventTrigger EventName="KeyDown">
<i:InvokeCommandAction Command="{Binding SearchFamilyCommand}" CommandParameter="{Binding Text, RelativeSource={RelativeSource AncestorType={x:Type TextBox}, Mode=FindAncestor}}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</ui:TextBox>
<ui:ListView
Grid.Row="1"
Grid.RowSpan="2"
Grid.Column="2"
d:ItemsSource="{d:SampleData}"
ItemsSource="{Binding FamilyPageListViewItems}"
SelectedItem="{Binding SelectedFamily}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding LvSelectionChangedCommand}" CommandParameter="{Binding SelectedItem, RelativeSource={RelativeSource AncestorType={x:Type ListView}, Mode=FindAncestor}}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<!--<ListView.View>
<GridView>
<GridViewColumn Header="缩略图" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<Image Source="{Binding ImageData}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding Title}" Header="名称" />
<GridViewColumn DisplayMemberBinding="{Binding Path}" Header="路径" />
<GridViewColumn DisplayMemberBinding="{Binding RevitVersion}" Header="版本" />
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Button
Command="{Binding DataContext.ImportFamilyCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"
CommandParameter="{Binding}"
Content="&#xedb7;载入"
FontFamily="{StaticResource BoxIcons}"
ToolTip="将族载入到当前项目" />
<Button
Command="{Binding DataContext.LocationFamilyFileCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"
CommandParameter="{Binding}"
Content="&#xea90;浏览"
FontFamily="{StaticResource BoxIcons}"
ToolTip="在资源管理器中浏览文件" />
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>-->
<ui:ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<Border
x:Name="border"
Margin="5"
Background="{TemplateBinding Background}"
BorderBrush="Transparent"
BorderThickness="2"
CornerRadius="5">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="True" />
<Condition Property="IsSelected" Value="False" />
</MultiTrigger.Conditions>
<Setter TargetName="border" Property="BorderBrush" Value="Gray" />
</MultiTrigger>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="border" Property="BorderBrush" Value="LightSkyBlue" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ui:ListView.ItemContainerStyle>
<ui:ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Width="{Binding (FrameworkElement.ActualWidth), RelativeSource={RelativeSource AncestorType={x:Type ScrollContentPresenter}}}" />
</ItemsPanelTemplate>
</ui:ListView.ItemsPanel>
<ui:ListView.ItemTemplate>
<DataTemplate>
<ui:Card Padding="0">
<Grid Width="170" Height="210">
<Grid.RowDefinitions>
<RowDefinition Height="170" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Image
Grid.Row="0"
Width="128"
Height="128"
Source="{Binding ImageData}"
Stretch="Uniform"
ToolTip="{Binding ToolTip}" />
<StackPanel
Grid.Row="0"
HorizontalAlignment="Center"
VerticalAlignment="Bottom"
Orientation="Horizontal">
<StackPanel.Style>
<Style TargetType="{x:Type StackPanel}">
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsMouseOver, RelativeSource={RelativeSource AncestorType={x:Type ListViewItem}, Mode=FindAncestor}}" Value="True">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Style>
<ui:Button
Appearance="Primary"
Command="{Binding DataContext.ImportFamilyCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}, Mode=FindAncestor}}"
CommandParameter="{Binding}"
Content="&#xEDB7;载入"
FontFamily="{StaticResource BoxIcons}"
ToolTip="将族载入到当前项目" />
<ui:Button
Appearance="Primary"
Command="{Binding DataContext.LocationFamilyFileCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}, Mode=FindAncestor}}"
CommandParameter="{Binding}"
Content="&#xEA90;定位"
FontFamily="{StaticResource BoxIcons}"
ToolTip="在资源管理器中浏览文件" />
<!--
CommandParameter="{Binding SelectedItem, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListView}}"
CommandParameter="{Binding DataContext, RelativeSource={RelativeSource Mode=Self}}" 等价于 CommandParameter="{Binding}"
-->
</StackPanel>
<TextBlock
Grid.Row="1"
Width="128"
Text="{Binding Title}"
TextAlignment="Center"
TextWrapping="WrapWithOverflow" />
</Grid>
</ui:Card>
</DataTemplate>
</ui:ListView.ItemTemplate>
<ui:ListView.Template>
<ControlTemplate TargetType="{x:Type ListView}">
<ScrollViewer
x:Name="scr"
HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Auto">
<i:Interaction.Triggers>
<i:EventTrigger EventName="ScrollChanged">
<i:InvokeCommandAction Command="{Binding LvScrollCommand}" CommandParameter="{Binding RelativeSource={RelativeSource AncestorType={x:Type ScrollViewer}, Mode=FindAncestor}}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<WrapPanel IsItemsHost="True" ScrollViewer.CanContentScroll="True" />
</ScrollViewer>
</ControlTemplate>
</ui:ListView.Template>
</ui:ListView>
<GridSplitter
Grid.Row="1"
Grid.Column="3"
Width="1"
HorizontalAlignment="Center"
ShowsPreview="True" />
<ui:DataGrid
Grid.Row="1"
Grid.Column="4"
Margin="5"
d:ItemsSource="{d:SampleData}"
AutoGenerateColumns="False"
CanUserAddRows="False"
IsReadOnly="True"
ItemsSource="{Binding SelectedItem.Parameters, ElementName=CbbSymbols, Mode=TwoWay}">
<ui:DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name}" Header="属性名" />
<DataGridTextColumn Binding="{Binding Value}" Header="属性值" />
</ui:DataGrid.Columns>
</ui:DataGrid>
<!--<StackPanel
Grid.Row="1"
Grid.Column="2"
Margin="5"
HorizontalAlignment="Right"
VerticalAlignment="Top">
<hc:ButtonGroup Style="{StaticResource ButtonGroupSolid}">
<RadioButton IsChecked="True" Style="{StaticResource RadioGroupItemHorizontalFirst}">
<hc:Interaction.Triggers>
<hc:EventTrigger EventName="Checked">
<hc:EventToCommand Command="{Binding ModifyLayout}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=RadioButton}}" />
</hc:EventTrigger>
</hc:Interaction.Triggers>
</RadioButton>
<RadioButton Style="{StaticResource RadioGroupItemHorizontalLast}">
<hc:Interaction.Triggers>
<hc:EventTrigger EventName="Checked">
<hc:EventToCommand Command="{Binding ModifyLayout}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=RadioButton}}" />
</hc:EventTrigger>
</hc:Interaction.Triggers>
</RadioButton>
</hc:ButtonGroup>
</StackPanel>-->
<ui:StackPanelEx
Grid.Row="0"
Grid.Column="4"
Orientation="Horizontal">
<ui:ComboBoxEx
x:Name="CbbSymbols"
ui:StackPanelEx.Fill="Fill"
DisplayMemberPath="Name"
ItemsSource="{Binding SymbolTypes, Mode=TwoWay}"
PlaceholderText="选择族类型"
SelectedItem="{Binding SelectedSymbolType, UpdateSourceTrigger=PropertyChanged}" />
<Button
Grid.Column="1"
Margin="5"
ui:StackPanelEx.Fill="Auto"
Command="{Binding ImportFamilySymbolCommand}"
Content="&#xEB1F;"
FontFamily="{StaticResource BoxIcons}"
ToolTip="载入类型" />
</ui:StackPanelEx>
<TextBlock
Grid.Row="2"
Grid.Column="0"
Margin="5"
Text="{Binding FamilyCount, Mode=OneWay, StringFormat=共计{}{0}个}" />
<ui:InfoBar
Grid.Row="2"
Grid.Column="2"
IsOpen="{Binding ActiveSnackbar}"
Message="{Binding Message}" />
<TextBlock
Grid.Row="2"
Grid.Column="4"
Text="{Binding RevitVersion, Mode=OneWay, StringFormat=当前文件版本Revit \{0\}}" />
</Grid>
</ui:FluentWindowEx>

View File

@@ -0,0 +1,13 @@
namespace ShrlAlgo.RvKits.RvFamily.FamilyLibrary
{
/// <summary>
/// LocalFamily.xaml 的交互逻辑.
/// </summary>
public partial class FamilyLibraryView
{
public FamilyLibraryView()
{
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,483 @@
using Autodesk.Revit.DB;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using FuzzySharp;
using Nice3point.Revit.Toolkit.External.Handlers;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using Settings = ShrlAlgo.RvKits.Properties.Settings;
namespace ShrlAlgo.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<FamilySymbolType> symbolTypes;
[ObservableProperty]
private bool activeSnackbar;
[ObservableProperty]
private WPFluent.Controls.InfoBar messageQueue = new();
[ObservableProperty]
private string message;
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)
{
//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;
}
}
/// <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 };
/* 项目“ShrlAlgo.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<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 WPFluent.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)
{
/* 项目“ShrlAlgo.RvKits (net481)”的未合并的更改
在此之前:
SubDirectories(subSubDirs, aNode);
在此之后:
FamilyLibraryViewModel.SubDirectories(subSubDirs, aNode);
*/
SubDirectories(subSubDirs, aNode);
}
nodeToAddTo.Items.Add(aNode);
}
}
}

View File

@@ -0,0 +1,93 @@
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using ShrlAlgo.Toolkit.Core.Extensions;
using System.IO;
using System.Windows.Media.Imaging;
namespace ShrlAlgo.RvKits.RvFamily.FamilyLibrary;
public partial class FamilyModel : ObservableObject
{
/// <summary>
/// 族库缩略图
/// </summary>
public BitmapSource ImageData => ImageExtensions.LoadFileImage(Path, 128, 128);
/// <summary>
/// 最近使用面板
/// </summary>
public BitmapImage BitmapImage { get; set; }
public FileInfo FileInfo { get; set; }
/// <summary>
/// 族库文件标题
/// </summary>
public string Title { get; set; }
public Family ReferenceFamily { get; set; }
public string ToolTip { get; set; }
public UIApplication UiApplication { get; set; }
public string Path { get; set; }
public string RevitVersion { get; set; }
public ElementId FamilyId => ReferenceFamily.Id;
//private bool CanPlace()
//{
// uiApplication.ActiveUIDocument.Document.is
// return ReferenceFamily.IsValidObject;
// .IsValidObject = true;
//}
[RelayCommand]
private static void PlaceRecentFamily(object obj)
{
try
{
if (obj is FamilyModel { ReferenceFamily: { } family } info)
{
var uidoc = info.UiApplication.ActiveUIDocument;
var doc = uidoc.Document;
if (family.IsValidObject && doc.PathName == family.Document.PathName)
{
var fs = doc.GetElement(family.GetFamilySymbolIds().FirstOrDefault()) as FamilySymbol;
uidoc.PostRequestForElementTypePlacement(fs);
}
//else
//{
// var docs = info.uiApplication.Application.Documents;
// foreach (Document d in docs)
// {
// if (d.PathName == family.Document.PathName)
// {
// List<ElementId> list = new List<ElementId>()
// {
// family.ViewId
// };
// doc.Invoke(ts =>
// {
// ElementTransformUtils.CopyElements(d, list, doc, null, new CopyPasteOptions());
// },"复制族");
// break;
// }
// }
//}
}
}
catch (Autodesk.Revit.Exceptions.OperationCanceledException) { }
catch (Exception e)
{
e.ToLog();
}
}
}

View File

@@ -0,0 +1,17 @@
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
namespace ShrlAlgo.RvKits.RvFamily.FamilyLibrary
{
public class LoadedFamilyDropHandler : IDropHandler
{
public void Execute(UIDocument document, object data)
{
ElementId familySymbolId = (ElementId)data;
if (document.Document.GetElement(familySymbolId) is FamilySymbol symbol)
{
document.PromptForFamilyInstancePlacement(symbol);
}
}
}
}

View File

@@ -0,0 +1,16 @@
namespace ShrlAlgo.RvKits.RvFamily.FamilyLibrary
{
public class FamilySymbolType
{
public List<Parameter> Parameters { get; set; } = new();
public string Name { get; set; }
public string Value { get; set; }
}
public class Parameter
{
public string Name { get; set; }
public string Value { get; set; }
public string TypeOfParameter { get; set; }
}
}

View File

@@ -0,0 +1,644 @@
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.IO.Packaging;
using System.Reflection;
using System.Text;
using System.Windows.Media.Imaging;
using System.Xml;
namespace ShrlAlgo.RvKits.RvFamily.FamilyLibrary
{
/// <summary>
/// 直接读取文件的信息不依赖RevitAPI
/// </summary>
internal static class RevitFileUtil
{
private static string _fileName;
public static Image PreviewImage { get; set; }
public static List<FamilySymbolType> SymbolTypes { get; set; }
public static StringBuilder FileInfo { get; set; }
public static StringBuilder Content { get; set; }
public static StringBuilder TransMissionData { get; set; }
public static string SafeName { get; set; }
public static string Product { get; set; }
public static string RevitVersion { get; set; }
public static string UpdateTime { get; set; }
/// <summary>
/// 图片资源转字节
/// </summary>
/// <param name="bitmapSource"></param>
/// <returns></returns>
public static byte[] BitSourceToArray(BitmapSource bitmapSource)
{
BitmapEncoder encoder = new JpegBitmapEncoder();
using (MemoryStream ms = new MemoryStream())
{
encoder.Frames.Add(BitmapFrame.Create(bitmapSource));
encoder.Save(ms);
return ms.ToArray();
}
}
public static StringBuilder GetFamilyInfo(List<FamilySymbolType> symbols)
{
StringBuilder sb = new StringBuilder();
foreach (FamilySymbolType symbol in symbols)
{
sb.Append($"族类型:{symbol.Name}{symbol.Value}\r\n");
foreach (Parameter param in symbol.Parameters)
{
sb.Append($" {param.Name}:{param.Value}\r\n");
}
}
return sb;
}
public static int GetPngStartingOffset(byte[] previewData)
{
bool markerFound = false;
int startingOffset = 0;
int previousValue = 0;
using (MemoryStream ms = new MemoryStream(previewData))
{
for (int i = 0; i < previewData.Length; i++)
{
int currentValue = ms.ReadByte();
// possible start of PNG file data
if (currentValue == 137) // 0x89
{
markerFound = true;
startingOffset = i;
previousValue = currentValue;
continue;
}
switch (currentValue)
{
case 80: // 0x50
if (markerFound && previousValue == 137)
{
previousValue = currentValue;
continue;
}
markerFound = false;
break;
case 78: // 0x4E
if (markerFound && previousValue == 80)
{
previousValue = currentValue;
continue;
}
markerFound = false;
break;
case 71: // 0x47
if (markerFound && previousValue == 78)
{
previousValue = currentValue;
continue;
}
markerFound = false;
break;
case 13: // 0x0D
if (markerFound && previousValue == 71)
{
previousValue = currentValue;
continue;
}
markerFound = false;
break;
case 10: // 0x0A
if (markerFound && previousValue == 26)
{
return startingOffset;
}
if (markerFound && previousValue == 13)
{
previousValue = currentValue;
continue;
}
markerFound = false;
break;
case 26: // 0x1A
if (markerFound && previousValue == 10)
{
previousValue = currentValue;
continue;
}
markerFound = false;
break;
}
}
}
return 0;
}
/// <summary>
/// 获取缩略图
/// </summary>
/// <param name="previewData"></param>
/// <returns></returns>
public static Image GetPreviewAsImage(byte[] previewData)
{
if (previewData == null || previewData.Length <= 0)
{
using (Bitmap newBitmap = new Bitmap(128, 128))
{
return newBitmap.Clone() as Bitmap;
}
}
// read past the Revit metadata to the start of the PNG image
int startingOffset = GetPngStartingOffset(previewData);
if (startingOffset == 0)
{
using (Bitmap newBitmap = new Bitmap(128, 128))
{
return newBitmap.Clone() as Bitmap;
}
}
try
{
byte[] pngDataBuffer = new byte[previewData.GetUpperBound(0) - startingOffset + 1];
// read the PNG image data into a byte array
using (MemoryStream ms = new MemoryStream(previewData))
{
ms.Position = startingOffset;
ms.Read(pngDataBuffer, 0, pngDataBuffer.Length);
}
byte[] decoderData = null;
// if the image data is valid
if (pngDataBuffer != null)
{
// use a memory stream to decode the PNG image data
// and copy the decoded data into a byte array
using (MemoryStream ms = new MemoryStream(pngDataBuffer))
{
PngBitmapDecoder decoder = new PngBitmapDecoder(ms, BitmapCreateOptions.PreservePixelFormat,
BitmapCacheOption.Default);
decoderData = BitSourceToArray(decoder.Frames[0]);
}
}
// if the decoded data is valie
if (decoderData != null && decoderData.Length > 0)
{
// use another memory stream to create a Bitmap
// and then an Image from that Bitmap
using (MemoryStream ms = new MemoryStream(decoderData))
{
using (Bitmap newBitmap = new Bitmap(ms))
{
using (Image newImage = newBitmap)
{
return newImage.Clone() as Image;
}
}
}
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
using (Bitmap newBitmap = new Bitmap(128, 128))
{
return newBitmap.Clone() as Bitmap;
}
}
public static string ParseDetailInfo(string detailInfo)
{
try
{
detailInfo = detailInfo.Trim();
int index = detailInfo.IndexOf(":");
string detailValue = detailInfo.Substring(detailInfo.IndexOf(":") + 1);
string detailKey = detailInfo.Substring(0, detailInfo.IndexOf(":"));
detailKey = detailKey.Trim().ToUpper().Replace(" ", string.Empty);
detailKey = PurgeUnprintableCharacters(detailKey);
detailValue = PurgeUnprintableCharacters(detailValue);
return $"{detailKey}:{detailValue}";
//Console.WriteLine($"{detailKey}:{detailValue}");
}
catch (Exception)
{
return detailInfo;
}
//switch (detailKey)
//{
// case "WORKSHARING":
// if (string.IsNullOrEmpty(detailValue))
// {
// WorkSharing = WorkSharingMode.Unknown;
// return;
// }
// string workSharing = detailValue.Replace(" ", string.Empty).Trim().ToUpper();
// switch (workSharing)
// {
// case "NOTENABLED":
// WorkSharing = WorkSharingMode.NotEnabled;
// break;
// case "LOCAL":
// WorkSharing = WorkSharingMode.Local;
// break;
// case "CENTRAL":
// WorkSharing = WorkSharingMode.Central;
// break;
// default:
// WorkSharing = WorkSharingMode.Unknown;
// break;
// }
// break;
// case "USERNAME":
// UserName = detailValue.Trim();
// break;
// case "CENTRALFILEPATH":
// CentralFilePath = detailValue.Trim();
// break;
// case "REVITBUILD":
// RevitBuild = detailValue.Trim();
// break;
// case "LASTSAVEPATH":
// LastSavedpath = detailValue.Trim();
// break;
// case "OPENWORKSETDEFAULT":
// OpenWorksetDefault = Convert.ToInt32(detailValue.Trim());
// break;
// default:
// Console.WriteLine($"{detailKey}:{detailValue}");
// //Debug.Assert(false, string.Format("{0} was not found in the case tests.", detailKey));
// break;
//}
}
public static StringBuilder ParseFileInfo(string unicodeData)
{
StringBuilder s = new StringBuilder();
string[] basicFileInfoParts = unicodeData.Split('\0');
foreach (string basicFileInfoPart in basicFileInfoParts)
{
if (basicFileInfoPart.IndexOf("\r\n", StringComparison.Ordinal) >= 0)
{
string[] detailInfoParts = basicFileInfoPart.Split(new[] { "\r\n" }, new StringSplitOptions());
foreach (string detailPart in detailInfoParts)
{
s.Append(ParseDetailInfo(detailPart) + "\r\n");
}
}
}
return s;
}
/// <summary>
/// 解析参数
/// </summary>
/// <param name="streamInfo"></param>
public static List<FamilySymbolType> ParseParameter(StreamInfo streamInfo)
{
XmlDocument document = new XmlDocument();
string xmlStr;
byte[] streamData;
using (Stream streamReader = streamInfo.GetStream(FileMode.Open, FileAccess.Read))
{
streamData = new byte[streamReader.Length];
streamReader.Read(streamData, 0, streamData.Length);
xmlStr = Encoding.UTF8.GetString(streamData);
document.LoadXml(xmlStr);
//string xmldocpath = Path.GetFileNameWithoutExtension(FileName) + ".xml";
//document.Save(xmldocpath);
//读取参数信息
XmlElement root = document.DocumentElement;
//节点前缀的命名空间
string nameSpace = root.GetNamespaceOfPrefix("A");
//string nameSpace = root.NamespaceURI;
XmlNamespaceManager nsmgr = new XmlNamespaceManager(document.NameTable);
;
nsmgr.AddNamespace("entry", nameSpace);
//族类型
XmlNodeList xnlist = document.GetElementsByTagName("A:part");
XmlNodeList fileinfo = document.GetElementsByTagName("A:design-file");
foreach (XmlNode xn in fileinfo)
{
if (xn.HasChildNodes)
{
foreach (XmlNode child in xn.ChildNodes)
{
if (child.Name == "A:title")
{
SafeName = child.InnerText;
}
if (child.Name == "A:product")
{
Product = child.InnerText;
}
if (child.Name == "A:product-version")
{
RevitVersion = child.InnerText;
}
if (child.Name == "A:product-updated")
{
UpdateTime = child.InnerText;
}
}
}
}
//XmlNode rootnode = document.SelectSingleNode("/entry/A: family/A:part", nsmgr);
//XmlNodeList xnlist = rootnode.ChildNodes;
List<FamilySymbolType> symbols = new List<FamilySymbolType>();
foreach (XmlNode xn in xnlist)
{
//XmlAttributeCollection attriCol = xn.Attributes;
//foreach (XmlAttribute xmlAttri in attriCol)
//{
// string name = xmlAttri.Name;
// string value = xmlAttri.Value;
//}
FamilySymbolType symbol = new FamilySymbolType();
if (xn.HasChildNodes)
{
foreach (XmlNode child in xn.ChildNodes)
{
Parameter p = new Parameter();
if (child.Name == "title")
{
symbol.Name = child.InnerText;
continue;
}
//族类型节点
p.Name = child.Name;
//族名称
p.Value = child.InnerText;
symbol.Parameters.Add(p);
}
}
symbols.Add(symbol);
}
return symbols;
}
}
public static void ParserRevitFile(string filename)
{
if (filename.EndsWith(".rvt") || filename.EndsWith(".rte") || filename.EndsWith(".rfa") ||
filename.EndsWith(".rft"))
{
_fileName = filename;
//获取Storageroot Object
BindingFlags bindingFlags = BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.InvokeMethod;
Type storageRootType = typeof(StorageInfo).Assembly.GetType("System.IO.Packaging.StorageRoot", true, false);
//Type storageRootType = typeof(StorageInfo).Assembly.GetType("System.IO.Packaging", true, false);
object[] file =
{
filename,
FileMode.Open,
FileAccess.Read,
FileShare.Read
};
StorageInfo Storage = (StorageInfo)storageRootType.InvokeMember("Open", bindingFlags, null, null, file);
//if (Storage != null)
//{
// storageRootType.InvokeMember("CloseTrigger", bindingFlags, null, Storage, file);
// //Console.Write($"{filename}文件无法作为结构存储,并打开打开");
//}
//var x = Storage.ThumbnailImage.GetPreviewAsImage();
//读取结构化存储文件
StreamInfo[] streams = Storage.GetStreams();
foreach (StreamInfo streamInfo in streams)
{
string unicodeData;
byte[] streamData = null;
using (Stream streamReader = streamInfo.GetStream(FileMode.Open, FileAccess.Read))
{
streamData = new byte[streamReader.Length];
streamReader.Read(streamData, 0, streamData.Length);
unicodeData = Encoding.Unicode.GetString(streamData);
//unicodeData = Encoding.UTF8.GetString(streamData);
}
if (streamInfo.Name.ToUpper().Equals("BASICFILEINFO"))
{
FileInfo = ParseFileInfo(unicodeData);
}
if (streamInfo.Name.ToUpper().Equals("PARTATOM"))
{
//Console.WriteLine("部分原子:\r\n" + ParsePartAtom(unicodeData));
if (filename.EndsWith(".rfa"))
{
SymbolTypes = ParseParameter(streamInfo);
//Console.WriteLine("族参数:\r\n" + GetFamilyInfo(symbols));
}
}
if (streamInfo.Name.ToUpper().Equals("TRANSMISSIONDATA"))
{
TransMissionData = ParseTransMissionData(unicodeData);
}
if (streamInfo.Name.ToUpper().Equals("REVITPREVIEW4.0"))
{
PreviewImage = ParsePreview(streamInfo);
}
if (streamInfo.Name.ToUpper().Equals("CONTENTS"))
{
Content = ParseContents(unicodeData);
}
}
}
//if (Storage != null)
//{
// try
// {
// storageRootType.InvokeMember("CloseTrigger", bindingFlags, null, Storage, file);
// }
// catch (Exception ex)
// {
// MessageBox.ShowAhead(ex.ViewMessage);
// }
//}
}
public static StringBuilder ParseTransMissionData(string unicodeData)
{
StringBuilder s = new StringBuilder();
string[] basicFileInfoParts = unicodeData.Split('\0');
foreach (string basicFileInfoPart in basicFileInfoParts)
{
if (basicFileInfoPart.IndexOf("\r\n") >= 0)
{
string[] detailInfoParts = basicFileInfoPart.Split(new[] { "\r\n" }, new StringSplitOptions());
foreach (string detailPart in detailInfoParts)
{
s.Append(ParseDetailInfo(detailPart) + "\r\n");
}
}
}
return s;
}
public static void ParseXmlDocument(XmlDocument document)
{
XmlNode rootNode = document.SelectSingleNode("A");
XmlNodeList xmlNodeList = rootNode?.ChildNodes;
if (xmlNodeList == null) return;
foreach (XmlNode xn in xmlNodeList)
{
if (true)
{
}
XmlAttributeCollection xnAttributes = xn.Attributes;
if (xnAttributes != null)
foreach (XmlAttribute attribute in xnAttributes)
{
string name = attribute.Name;
string value = attribute.Value;
}
if (xn.HasChildNodes)
{
}
}
}
/// <summary>
/// 清理无效字符
/// </summary>
/// <param name="oldValue"></param>
/// <returns></returns>
public static string PurgeUnprintableCharacters(string oldValue)
{
StringBuilder sb = new StringBuilder();
char[] oldValueArray = oldValue.ToCharArray();
foreach (char letter in oldValueArray)
{
int decimalValue = letter;
if (decimalValue >= 32 && decimalValue <= 126)
{
sb.Append(letter);
}
}
oldValue = sb.ToString();
sb.Length = 0;
sb.Capacity = 0;
sb = null;
return oldValue;
}
private static StringBuilder ParseContents(string unicodeData)
{
StringBuilder s = new StringBuilder();
string[] basicFileInfoParts = unicodeData.Split('\0');
foreach (string basicFileInfoPart in basicFileInfoParts)
{
if (basicFileInfoPart.IndexOf("\r\n", StringComparison.Ordinal) >= 0)
{
string[] detailInfoParts = basicFileInfoPart.Split(new[] { "\r\n" }, new StringSplitOptions());
foreach (string detailPart in detailInfoParts)
{
s.Append(ParseDetailInfo(detailPart) + "\r\n");
}
}
}
return s;
}
private static StringBuilder ParsePartAtom(string unicodeData)
{
StringBuilder s = new StringBuilder();
string[] basicFileInfoParts = unicodeData.Split('\0');
foreach (string basicFileInfoPart in basicFileInfoParts)
{
if (basicFileInfoPart.IndexOf("\r\n", StringComparison.Ordinal) >= 0)
{
string[] detailInfoParts = basicFileInfoPart.Split(new[] { "\r\n" }, new StringSplitOptions());
foreach (string detailPart in detailInfoParts)
{
s.Append(ParseDetailInfo(detailPart) + "\r\n");
}
}
}
return s;
}
private static Image ParsePreview(StreamInfo stream)
{
byte[] streamData = null;
using (Stream streamReader = stream.GetStream(FileMode.Open, FileAccess.Read))
{
streamData = new byte[streamReader.Length];
streamReader.Read(streamData, 0, streamData.Length);
//unicodeData = Encoding.Unicode.GetString(streamData);
//unicodeData = Encoding.UTF8.GetString(streamData);
}
return GetPreviewAsImage(streamData);
}
}
}

View File

@@ -0,0 +1,19 @@
using Autodesk.Revit.Attributes;
using Nice3point.Revit.Toolkit.External;
using ShrlAlgo.Toolkit.Core.Heplers;
using System.Windows;
namespace ShrlAlgo.RvKits.RvFamily;
[Transaction(TransactionMode.Manual)]
[Regeneration(RegenerationOption.Manual)]
public class FamilyProcessorCmd : ExternalCommand
{
public override void Execute()
{
WinDialogHelper.ShowModeless<FamilyProcessorView>(new FamilyProcessorViewModel(UiApplication));
}
}

View File

@@ -0,0 +1,172 @@
<ui:FluentWindowEx
x:Class="ShrlAlgo.RvKits.RvFamily.FamilyProcessorView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:local="clr-namespace:ShrlAlgo.RvKits.RvFamily"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="https://github.com/ShrlAlgo/WPFluent"
Title="族复用"
Width="380"
Height="600"
MinWidth="380"
MinHeight="400"
d:DataContext="{d:DesignInstance Type=local:FamilyProcessorViewModel}"
mc:Ignorable="d">
<Window.Resources>
<ResourceDictionary Source="pack://application:,,,/ShrlAlgo.RvKits;component/WPFUI.xaml" />
</Window.Resources>
<TabControl Margin="5,5,5,5">
<TabItem Header="保存族">
<ui:AutoGridEx
ChildMargin="5"
Columns="*,*"
Rows="*,Auto,Auto,Auto">
<DataGrid
x:Name="FamilySaveDg"
Grid.ColumnSpan="2"
d:ItemsSource="{d:SampleData}"
AutoGenerateColumns="False"
CanUserAddRows="False"
IsReadOnly="True"
ItemsSource="{Binding FamilyCollection}"
SelectionMode="Extended">
<!--<ui:DataGrid.RowHeaderTemplate>
<DataTemplate>
<Grid Width="35">
<CheckBox HorizontalAlignment="Center" IsChecked="{Binding IsSelected, RelativeSource={RelativeSource AncestorType={x:Type DataGridRow}}}" />
</Grid>
</DataTemplate>
</ui:DataGrid.RowHeaderTemplate>-->
<DataGrid.Columns>
<DataGridCheckBoxColumn
Width="60"
Binding="{Binding IsSelected, Mode=OneWayToSource, RelativeSource={RelativeSource AncestorType={x:Type DataGridRow}}}"
ElementStyle="{StaticResource DataGridCheckBoxElementDefaultStyle}"
Header="选择" />
<DataGridTextColumn Binding="{Binding FamilyCategory.Name}" Header="族类别" />
<DataGridTextColumn Binding="{Binding Name}" Header="族名称" />
</DataGrid.Columns>
</DataGrid>
<GroupBox
Grid.Row="1"
Grid.Column="1"
Header="保存选项">
<StackPanel>
<RadioButton Content="覆盖存在文件" IsChecked="{Binding IsOverride, UpdateSourceTrigger=PropertyChanged}" />
<RadioButton Content="忽略存在文件" />
</StackPanel>
</GroupBox>
<StackPanel
Grid.Row="1"
Grid.Column="0"
VerticalAlignment="Center">
<CheckBox Content="添加族类别文件夹" IsChecked="{Binding CreateCategoryFolder}" />
<CheckBox Content="文件名添加族类别" IsChecked="{Binding AddCategoryPrefix}" />
<CheckBox Content="以三维为默认视图" IsChecked="{Binding View3dAsDefault}" />
</StackPanel>
<ui:TextBox
PlaceholderText="保存路径"
Text="{Binding PathToSaveFamily}"
TextOptions.TextFormattingMode="Display" />
<ui:Button
HorizontalAlignment="Stretch"
Command="{Binding SelectDirectoryCommand}"
Content="路径选择"
Cursor="Hand"
Icon="{ui:FontIcon '&#xEADF;',
FontFamily={StaticResource BoxIcons}}" />
<ComboBox
DisplayMemberPath="Title"
ItemsSource="{Binding SourceDocsList}"
SelectedItem="{Binding SourceDoc, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Text="源文档">
<!--<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding GetFamiliesCommand}" CommandParameter="{Binding}" />
</i:EventTrigger>
</i:Interaction.Triggers>-->
</ComboBox>
<ui:Button
HorizontalAlignment="Stretch"
Command="{Binding SaveFamiliesCommand}"
CommandParameter="{Binding SelectedItems, ElementName=FamilySaveDg}"
Content="导出保存"
Icon="{ui:FontIcon Glyph=&#xEACE;,
FontFamily={StaticResource BoxIcons}}" />
</ui:AutoGridEx>
</TabItem>
<TabItem Header="传递族">
<ui:AutoGridEx
ChildMargin="5"
Columns="*,Auto"
Rows="*,Auto,Auto">
<DataGrid
x:Name="familyTransmitDg"
Grid.ColumnSpan="2"
d:ItemsSource="{d:SampleData}"
AutoGenerateColumns="False"
CanUserAddRows="False"
IsReadOnly="True"
ItemsSource="{Binding FamilyCollection}"
SelectionMode="Extended">
<!--<ui:DataGrid.RowHeaderTemplate>
<DataTemplate>
<Grid Width="35">
<CheckBox HorizontalAlignment="Center" IsChecked="{Binding IsSelected, RelativeSource={RelativeSource AncestorType={x:Type DataGridRow}}}" />
</Grid>
</DataTemplate>
</ui:DataGrid.RowHeaderTemplate>-->
<DataGrid.Columns>
<DataGridCheckBoxColumn
Width="60"
Binding="{Binding IsSelected, Mode=OneWayToSource, RelativeSource={RelativeSource AncestorType={x:Type DataGridRow}}}"
ElementStyle="{StaticResource DataGridCheckBoxElementDefaultStyle}"
Header="选择" />
<DataGridTextColumn Binding="{Binding FamilyCategory.Name}" Header="族类别" />
<DataGridTextColumn Binding="{Binding Name}" Header="族名称" />
</DataGrid.Columns>
</DataGrid>
<ComboBox
Grid.Row="1"
Grid.Column="0"
DisplayMemberPath="Title"
ItemsSource="{Binding SourceDocsList, Mode=TwoWay}"
SelectedItem="{Binding SourceDoc, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Text="源文档">
<!--<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding GetTargetDocListCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>-->
</ComboBox>
<Button
Grid.Row="1"
Grid.Column="1"
Command="{Binding TransmitFamilyCommand}"
CommandParameter="{Binding SelectedItems, ElementName=familyTransmitDg}"
Content="&#xEA84;"
FontFamily="{StaticResource BoxIcons}"
ToolTip="传递" />
<ComboBox
Grid.Row="2"
Grid.Column="0"
DisplayMemberPath="Title"
ItemsSource="{Binding TargetDocsList, Mode=TwoWay}"
SelectedItem="{Binding TargetDoc, UpdateSourceTrigger=PropertyChanged}"
Text="目标文档" />
<Button
Grid.Row="2"
Grid.Column="1"
Command="{Binding CancelCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}, Mode=FindAncestor}}"
Content="&#xEC84;"
FontFamily="{StaticResource BoxIcons}"
ToolTip="关闭" />
</ui:AutoGridEx>
</TabItem>
</TabControl>
</ui:FluentWindowEx>

View File

@@ -0,0 +1,15 @@
using System.Windows;
namespace ShrlAlgo.RvKits.RvFamily
{
/// <summary>
/// WpfMassSaveFamilies.xaml 的交互逻辑
/// </summary>
public partial class FamilyProcessorView
{
public FamilyProcessorView()
{
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,558 @@
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Nice3point.Revit.Toolkit.External.Handlers;
using System.Collections;
using System.Collections.ObjectModel;
using System.IO;
using System.Text;
using System.Windows;
using System.Windows.Controls;
namespace ShrlAlgo.RvKits.RvFamily;
public partial class FamilyProcessorViewModel : ObservableObject
{
[ObservableProperty]
private bool addCategoryPrefix;
[ObservableProperty]
private bool createCategoryFolder;
[ObservableProperty]
private IList<ElementType> familyEditCollection;
//private readonly List<TreeModel> familyNodes = new();
[ObservableProperty]
private string findStr;
private readonly ActionEventHandler handler;
[ObservableProperty]
private bool isOverride = true;
[ObservableProperty]
private int modifyNameIndex;
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(SaveFamiliesCommand))]
private string pathToSaveFamily;
[ObservableProperty]
private string prefix;
[ObservableProperty]
private string replaceStr;
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(TransmitFamilyCommand), nameof(SaveFamiliesCommand))]
private Document sourceDoc;
[ObservableProperty]
private string suffix;
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(TransmitFamilyCommand))]
private Document targetDoc;
//private readonly ExternalEvent saveEvent;
//private readonly SaveFamilyHandler handler;
//便于类中各处进行调用,故在此处添加字段
private readonly UIApplication uiapp;
[ObservableProperty]
private bool view3dAsDefault;
[ObservableProperty]
public List<Family> familyCollection = new();
[ObservableProperty]
public List<Document> sourceDocsList;
[ObservableProperty]
public List<Document> targetDocsList;
public FamilyProcessorViewModel(UIApplication uiapp)
{
this.uiapp = uiapp;
handler = new ActionEventHandler();
FamilyEditCollection = uiapp.ActiveUIDocument.Document
.OfClasses(typeof(HostObjAttributes), typeof(FamilySymbol))
.Cast<ElementType>()
.ToList();
SourceDocsList = AllDocuments;
//FamilyEditCollection = uiApplication.ActiveUIDocument.Document.QueryElementTypeByType<ElementType>().Cast<ElementType>().ToList();
}
//private List<TreeModel> AddFamilyToTreeView()
//{
// List<TreeModel> familiesTree = new();
// #region 族
// if (SourceDoc == null)
// {
// return null;
// }
// var categories = SourceDoc.Settings.Categories;
// var familyCollector = SourceDoc.OfClass<Family>().Cast<Family>().ToList();
// var familySymbolCollector = SourceDoc.OfClass<FamilySymbol>().Cast<FamilySymbol>().ToList();
// //ErrorModels<ElementId> dimensionTypeId = (from ElementToMove i in new FilteredElementCollector(sourceDoc).OfClass(typeof(DimensionType)) select i.ViewId).ToList();
// //var elementTypes = new FilteredElementCollector(sourceDoc).OfClass(typeof(ElementType));
// //ElementClassFilter familysymbolfilter = new ElementClassFilter(typeof(FamilySymbol));
// //ElementClassFilter hostsymbolFilter = new ElementClassFilter(typeof(HostObjAttributes));
// //LogicalOrFilter andfilter = new LogicalOrFilter(familysymbolfilter, hostsymbolFilter);
// //var familiesSymbolCollector = new FilteredElementCollector(sourceDoc).WherePasses(andfilter);
// foreach (Category category in categories)
// {
// TreeModel familyCategoryNode =
// new()
// {
// //familyCategory.ViewId = category.Name;
// Name = category.Name,
// IsExpanded = false
// };
// foreach (var family in familyCollector)
// {
// if (family.FamilyCategory.Name == category.Name)
// {
// TreeModel familyNode =
// new()
// {
// //familyNode.ViewId = family.Name;
// Name = family.Name,
// IsExpanded = false,
// Parent = familyCategoryNode
// };
// familyCategoryNode.Children.Add(familyNode);
// //获取族及其族类型,作为加载对象合集
// familyNodes.Add(familyNode);
// foreach (var familySymbol in familySymbolCollector)
// {
// if (familySymbol.FamilyName == family.Name)
// {
// TreeModel familySymbolNode =
// new()
// {
// //familiesSymbolNode.ViewId = familySymbol.Name;
// Name = familySymbol.Name,
// Parent = familyNode
// };
// familyNode.Children.Add(familySymbolNode);
// }
// }
// }
// }
// if (familyCategoryNode.Children.Count != 0)
// {
// FamilyNodesList.Add(familyCategoryNode);
// }
// }
// #endregion 族
// var hostObjectCollector = new FilteredElementCollector(SourceDoc)
// .OfClass(typeof(HostObjAttributes))
// .Cast<HostObjAttributes>()
// .ToList();
// //IList<string> categoryNames = (from HostObjAttributes ele in hostObjectCollector
// // select ele.Category.Name).ToList();
// //var elementTypes = new FilteredElementCollector(sourceDoc).OfClass(typeof(ElementType));
// //ErrorModels<string> ss1 = categoryNames.Distinct().ToList();
// foreach (var obj in hostObjectCollector)
// {
// var categoryName = obj.Category.Name;
// var familyName = obj.FamilyName;
// var familySymbolName = obj.Name;
// #region categoryRegion
// TreeModel familyCategoryNode = null;
// foreach (var t in familiesTree)
// {
// if (t.ToolTip.Equals(categoryName)) //遍历是否找到相同的节点
// {
// familyCategoryNode = t; //有则传递给当前类别节点
// break;
// }
// }
// if (familyCategoryNode == null)
// {
// TreeModel t = new() { Name = categoryName, IsExpanded = false };
// familyCategoryNode = t;
// familiesTree.Add(familyCategoryNode);
// }
// #endregion categoryRegion
// #region familyRegion
// TreeModel familyNode = null;
// foreach (var t in familyCategoryNode.Children)
// {
// if (t.ToolTip.Equals(categoryName + "-" + familyName))
// {
// familyNode = t;
// break;
// }
// }
// if (familyNode == null)
// {
// TreeModel t =
// new()
// {
// Name = familyName,
// IsExpanded = false,
// Parent = familyCategoryNode
// };
// familyCategoryNode.Children.Add(t);
// familyNode = t;
// familyNodes.Add(familyNode);
// }
// #endregion familyRegion
// #region familySymbol
// TreeModel familySymbolNode = null;
// foreach (var t in familyNode.Children)
// {
// if (t.ToolTip.Equals(familyName + "-" + familySymbolName))
// {
// familySymbolNode = t;
// break;
// }
// }
// if (familySymbolNode == null)
// {
// TreeModel t =
// new()
// {
// Name = familySymbolName,
// IsExpanded = false,
// Parent = familyNode
// };
// familyNode.Children.Add(t);
// }
// #endregion familySymbol
// //TreeModel familyNode = new TreeModel();
// //familyNode.Name = obj.FamilyName;
// ////familyNode.Name = obj.FamilyName;
// //familyNode.IsExpanded = false;
// //familyNode.Parent = categoryNode;
// //categoryNode.Children.Add(familyNode);
// //familyNodes.Add(familyNode);
// ////if (obj.Name == familyNode.Name)
// ////{
// //TreeModel familiesSymbolNode = new TreeModel();
// ////familiesSymbolNode.ViewId = familySymbol.Name;
// //familiesSymbolNode.Name = obj.Name;
// //familiesSymbolNode.Parent = familyNode;
// //familyNode.Children.Add(familiesSymbolNode);
// //}
// }
// familiesTree.Sort();
// return familiesTree;
// //FamilyTreeView.UpdateLayout();
//}
[RelayCommand]
private static void Cancel(object obj)
{
if (obj is System.Windows.Window window)
{
window.DialogResult = false;
}
}
/// <summary>
/// 获取当前所有文档
/// </summary>
/// <returns></returns>
private List<Document> ListOfOpenedDocument()
{
var documents = new List<Document>();
foreach (Document document in uiapp.Application.Documents)
{
if (!document.IsLinked && !document.IsFamilyDocument)
{
documents.Add(document);
}
}
return documents;
}
partial void OnSourceDocChanged(Document value)
{
FamilyCollection = SourceDoc.OfClass<Family>().OfType<Family>().Where(f => f.IsEditable).ToList();
TargetDocsList = new(
AllDocuments.Where(
d =>
(d.PathName != null && SourceDoc?.PathName != null && d.PathName != SourceDoc.PathName)
|| (SourceDoc != null && d.Title != SourceDoc.Title)
|| SourceDoc == null
)
);
}
[RelayCommand(CanExecute = nameof(CanSaveFamilies))]
private void SaveFamilies(object obj)
{
var items = (System.Collections.IList)obj;
var collection = items.Cast<Family>();
var selectedItems = collection.ToList();
if (!selectedItems.Any())
{
return;
}
handler.Raise(_ =>
{
StringBuilder sb = new();
if (!Directory.Exists(PathToSaveFamily))
{
var dr = MessageBox.Show("路径不存在,是否创建该路径", "提示", MessageBoxButton.OKCancel, MessageBoxImage.Information);
if (dr == MessageBoxResult.OK)
{
try
{
Directory.CreateDirectory(PathToSaveFamily);
}
catch (Exception ex)
{
ex.Message.ToLog();
MessageBox.Show("无法创建保存路径", "错误", MessageBoxButton.YesNo, MessageBoxImage.Error);
}
}
}
else
{
//FileInfo fileInfo = new FileInfo(text3);
foreach (var family in selectedItems)
{
var familyFileInfo = family.Name;
//string categoryInfo = family.Category.Name;
var directory = PathToSaveFamily + "\\";
var categoryInfo = family.FamilyCategory.Name;
if (CreateCategoryFolder)
{
directory += $"{categoryInfo}\\";
DirectoryInfo directoryInfo = new(directory);
if (!directoryInfo.Exists)
{
directoryInfo.Create();
}
}
if (AddCategoryPrefix)
{
familyFileInfo = $"({categoryInfo}){familyFileInfo}";
}
var completeDir = directory + familyFileInfo + ".rfa";
try
{
FileInfo fileInfo = new(completeDir);
if (fileInfo.Exists)
{
if (IsOverride)
{
fileInfo.Delete();
}
}
if (family.IsEditable)
{
var editFamily = SourceDoc.EditFamily(family);
if (View3dAsDefault)
{
Set3DView(editFamily);
}
editFamily.SaveAs(completeDir);
editFamily.Close(false);
}
else
{
sb.AppendLine($"{categoryInfo}-{family.Name}");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
}
if (!string.IsNullOrEmpty($"{sb}"))
{
MessageBox.Show($"以下族无法导出:\n{sb}", "导出错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
//saveEvent.Raise();
}
[RelayCommand]
private void SelectDirectory()
{
WPFluent.Controls.VistaFolderBrowserDialog dialog = new();
//dialog.Description = "请选择文件路径";
//dialog.SeletcedPath = @"C:\Users\ZGG\Documents";
if (dialog.ShowDialog() == true)
{
var savePath = dialog.SelectedPath;
PathToSaveFamily = savePath;
}
}
private static void Set3DView(Document doc)
{
try
{
Transaction transaction = new(doc);
transaction.Start();
doc.GetDocumentPreviewSettings();
SaveAsOptions saveAsOptions = new();
if (doc.GetDocumentPreviewSettings().PreviewViewId.Equals(ElementId.InvalidElementId))
{
var startingViewSettings = StartingViewSettings.GetStartingViewSettings(doc);
if (!startingViewSettings.ViewId.Equals(ElementId.InvalidElementId))
{
saveAsOptions.PreviewViewId = startingViewSettings.ViewId;
}
else
{
var viewCollector = new FilteredElementCollector(doc).OfClass(typeof(View));
var viewEnum = viewCollector
.Cast<View>()
.Where(view => view.ViewType == ViewType.ThreeD && !view.IsTemplate);
var flag = true;
foreach (View view in (IEnumerable)viewEnum)
{
if (view.IsTemplate)
{
continue;
}
saveAsOptions.PreviewViewId = view.Id;
flag = false;
break;
}
if (flag)
{
foreach (
View view in (IEnumerable)
viewCollector
.Cast<View>()
.Where(viewNot3D =>
{
return viewNot3D.ViewType
is ViewType.FloorPlan
or ViewType.EngineeringPlan
or ViewType.Elevation
|| (viewNot3D.ViewType == ViewType.Section && !viewNot3D.IsTemplate);
})
)
{
if (view.IsTemplate)
{
continue;
}
saveAsOptions.PreviewViewId = view.Id;
break;
}
}
}
}
transaction.Commit();
}
catch
{
// ignored
}
}
[RelayCommand(CanExecute = nameof(CanTransmitFamilies))]
private void TransmitFamily(object obj)
{
var items = (IList)obj;
var collection = items.Cast<Family>();
var selectedItems = collection.ToList();
if (!selectedItems.Any())
{
return;
}
handler.Raise(_ =>
{
TargetDoc.Invoke(
_ =>
{
CopyPasteOptions copyPasteOptions = new();
//copyPasteOptions.SetDuplicateTypeNamesHandler(copyPasteOptions.GetDuplicateTypeNamesHandler());
var ids = selectedItems.ConvertAll(f => f.Id);
ElementTransformUtils.CopyElements(SourceDoc, ids, TargetDoc, null, copyPasteOptions);
},
"传递族"
);
});
}
private List<Document> AllDocuments => ListOfOpenedDocument();
private bool CanSaveFamilies => PathToSaveFamily != null && SourceDoc != null;
private bool CanTransmitFamilies => SourceDoc != null && TargetDoc != null;
}
//public class CopyHandlerOk : IDuplicateTypeNamesHandler
//{
// public DuplicateTypeAction OnDuplicateTypeNamesFound(DuplicateTypeNamesHandlerArgs args)
// {
// return DuplicateTypeAction.UseDestinationTypes;
// }
//}
//public class CopyHandlerAbort : IDuplicateTypeNamesHandler
//{
// public DuplicateTypeAction OnDuplicateTypeNamesFound(DuplicateTypeNamesHandlerArgs args)
// {
// return DuplicateTypeAction.Abort;
// }
//}

View File

@@ -0,0 +1,32 @@
using Autodesk.Revit.DB;
using CommunityToolkit.Mvvm.ComponentModel;
using ShrlAlgo.Toolkit.Mvvm.Attributes;
namespace ShrlAlgo.RvKits.RvFamily;
public partial class RenameFamilyItem : ObservableValidator
{
[ObservableProperty]
private bool isSelected;
[ObservableProperty]
[UndefinedChar]
[NotifyDataErrorInfo]
private string newFamilyName;
[ObservableProperty]
private string oldFamilyName;
partial void OnIsSelectedChanged(bool value)
{
if (value == false)
{
NewFamilyName = string.Empty;
}
}
public Family Family { get; set; }
public string CategoryName { get; set; }
}

View File

@@ -0,0 +1,27 @@
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Nice3point.Revit.Toolkit.External;
using System;
using System.Windows;
namespace ShrlAlgo.RvKits.RvFamily
{
/// <summary>
/// Revit执行命令
/// </summary>
[Transaction(TransactionMode.Manual)]
[Regeneration(RegenerationOption.Manual)]
public class RenameFamilyNameCmd : ExternalCommand
{
public override void Execute()
{
RenameFamilyViewModel viewmodel = new(UiApplication);
RenameFamilyView win = new(viewmodel);
win.ShowDialog();
}
}
}

View File

@@ -0,0 +1,269 @@
<ui:FluentWindowEx
x:Class="ShrlAlgo.RvKits.RvFamily.RenameFamilyView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ShrlAlgo.RvKits.RvFamily"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="https://github.com/ShrlAlgo/WPFluent"
xmlns:attachedProps="clr-namespace:ShrlAlgo.Toolkit.Mvvm.AttachedProps"
xmlns:validationRules="clr-namespace:ShrlAlgo.Toolkit.Mvvm.ValidationRules"
Title="重命名族"
Width="900"
Height="600"
d:DataContext="{d:DesignInstance local:RenameFamilyViewModel}"
mc:Ignorable="d">
<Window.Resources>
<ResourceDictionary Source="pack://application:,,,/ShrlAlgo.RvKits;component/WPFUI.xaml" />
</Window.Resources>
<ui:AutoGridEx
ChildMargin="5"
Columns="250,*,*,*"
Rows="*,Auto">
<ui:AutoGridEx
Grid.RowSpan="2"
Columns="*"
Rows="*,Auto,Auto">
<GroupBox Header="族类别">
<ListBox
x:Name="LbCategories"
Height="400"
d:ItemsSource="{d:SampleData ItemCount=5}"
DisplayMemberPath="Key"
ItemsSource="{Binding Collection, Mode=OneWay}"
SelectionMode="Multiple">
<!--<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>-->
<!--<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>-->
<!--<ListBox.ItemTemplate>
<DataTemplate>
<Border CornerRadius="5" />
</DataTemplate>
</ListBox.ItemTemplate>-->
<!--<ListBox.ItemContainerStyle>
<Style />
</ListBox.ItemContainerStyle>-->
<b:Interaction.Triggers>
<b:EventTrigger EventName="SelectionChanged">
<b:InvokeCommandAction Command="{Binding GetRenameItemsCommand}" CommandParameter="{Binding SelectedItems, RelativeSource={RelativeSource AncestorType={x:Type ListBox}, Mode=FindAncestor}}" />
</b:EventTrigger>
</b:Interaction.Triggers>
<!--<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType=ListBoxItem}}" />
<TextBlock VerticalAlignment="Center" Text="{Binding Value}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>-->
</ListBox>
</GroupBox>
<DockPanel>
<CheckBox Content="全选">
<b:Interaction.Triggers>
<b:EventTrigger EventName="Checked">
<b:CallMethodAction MethodName="SelectAll" TargetObject="{Binding ElementName=LbCategories}" />
</b:EventTrigger>
<b:EventTrigger EventName="Unchecked">
<b:CallMethodAction MethodName="UnselectAll" TargetObject="{Binding ElementName=LbCategories}" />
</b:EventTrigger>
</b:Interaction.Triggers>
</CheckBox>
<TextBlock
HorizontalAlignment="Right"
VerticalAlignment="Center"
Text="{Binding CategoryCount, StringFormat=类别数:{}{0:D}}" />
</DockPanel>
<ui:TextBoxEx PlaceholderText="过滤族类别" Text="{Binding SearchText, UpdateSourceTrigger=PropertyChanged}" />
</ui:AutoGridEx>
<DataGrid
x:Name="DgRename"
Grid.Row="0"
Grid.Column="1"
Grid.ColumnSpan="3"
attachedProps:TextSearch.SearchValue="{Binding Text, ElementName=TbFound, UpdateSourceTrigger=PropertyChanged}"
AutoGenerateColumns="False"
CanUserAddRows="False"
HeadersVisibility="Column"
IsEnabled="{Binding CanInput}"
ItemsSource="{Binding RenameItems}"
SelectionUnit="Cell">
<DataGrid.Resources>
<Style BasedOn="{StaticResource DefaultDataGridCellStyle}" TargetType="{x:Type DataGridCell}">
<!--<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />-->
<Setter Property="attachedProps:TextSearch.IsTextMatch">
<Setter.Value>
<MultiBinding Converter="{StaticResource SearchFamilyValueConverter}">
<Binding Path="Content.Text" RelativeSource="{RelativeSource Mode=Self}" />
<Binding Path="(attachedProps:TextSearch.SearchValue)" RelativeSource="{RelativeSource Mode=Self}" />
<Binding RelativeSource="{RelativeSource Mode=Self}" />
</MultiBinding>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="attachedProps:TextSearch.IsTextMatch" Value="True">
<Setter Property="Foreground" Value="SkyBlue" />
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.Resources>
<DataGrid.ColumnHeaderStyle>
<Style BasedOn="{StaticResource DefaultDataGridColumnHeaderStyle}" TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="HorizontalContentAlignment" Value="Center" />
</Style>
</DataGrid.ColumnHeaderStyle>
<DataGrid.Columns>
<DataGridCheckBoxColumn
MinWidth="80"
Binding="{Binding IsSelected, UpdateSourceTrigger=PropertyChanged}"
EditingElementStyle="{StaticResource DataGridCheckBoxEditingElementDefaultStyle}"
ElementStyle="{StaticResource DataGridCheckBoxElementDefaultStyle}">
<DataGridCheckBoxColumn.Header>
<Border Background="Transparent">
<CheckBox
HorizontalAlignment="Center"
Content="全选"
IsChecked="{Binding DataContext.IsAllItemsSelected, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />
</Border>
</DataGridCheckBoxColumn.Header>
<!--<DataGridCheckBoxColumn.HeaderStyle>
<Style BasedOn="{StaticResource DefaultDataGridColumnHeaderStyle}" TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="HorizontalContentAlignment" Value="Center" />
</Style>
</DataGridCheckBoxColumn.HeaderStyle>-->
</DataGridCheckBoxColumn>
<DataGridTextColumn
MinWidth="80"
Binding="{Binding CategoryName}"
Header="族类别"
IsReadOnly="True">
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn
MinWidth="80"
Binding="{Binding OldFamilyName}"
Header="族名称"
IsReadOnly="True">
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn
MinWidth="80"
Binding="{Binding NewFamilyName, UpdateSourceTrigger=PropertyChanged}"
EditingElementStyle="{StaticResource DefaultTextBoxStyle}"
Header="新族名称">
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
<GroupBox Header="前/后缀">
<UniformGrid Columns="1">
<ui:TextBox
x:Name="CbPrefix"
Margin="5"
IsEnabled="{Binding CanInput}"
PlaceholderText="前缀">
<Binding Path="PrefixText" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<validationRules:UndefinedCharRules ValidatesOnTargetUpdated="True" />
</Binding.ValidationRules>
</Binding>
</ui:TextBox>
<!--<TextBox
x:Name="TbPrefix"
materialDesign:HintAssist.Hint="前缀"
IsEnabled="{Binding CanInput}">
<TextBox.Text>
<Binding Path="PrefixText" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<validationRules:UndefinedCharRules ValidatesOnTargetUpdated="True" />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>-->
<ui:TextBox
x:Name="TbSuffix"
Margin="5"
IsEnabled="{Binding CanInput}"
PlaceholderText="后缀">
<Binding Path="SuffixText" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<validationRules:UndefinedCharRules ValidatesOnTargetUpdated="True" />
</Binding.ValidationRules>
</Binding>
</ui:TextBox>
</UniformGrid>
</GroupBox>
<GroupBox Header="查找/替换">
<StackPanel>
<ui:TextBox
x:Name="TbFound"
Margin="5"
IsEnabled="{Binding CanInput}"
PlaceholderText="查找">
<Binding Path="FoundText" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<validationRules:UndefinedCharRules ValidatesOnTargetUpdated="True" />
</Binding.ValidationRules>
</Binding>
</ui:TextBox>
<ui:TextBox
x:Name="TbReplace"
Margin="5"
IsEnabled="{Binding CanInput}"
PlaceholderText="替换">
<Binding Path="ReplaceText" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<validationRules:UndefinedCharRules ValidatesOnTargetUpdated="True" />
</Binding.ValidationRules>
</Binding>
</ui:TextBox>
</StackPanel>
</GroupBox>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<GroupBox Grid.Row="0" Header="连接符">
<TextBox x:Name="TbSeparator" IsEnabled="{Binding CanInput}">
<Binding Path="Separator" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<validationRules:UndefinedCharRules ValidatesOnTargetUpdated="True" />
</Binding.ValidationRules>
</Binding>
</TextBox>
</GroupBox>
<Button
Grid.Row="1"
HorizontalAlignment="Stretch"
Command="{Binding ModifyNameCommand}"
Content="修改名称"
ToolTip="勾选要修改的项进行修改" />
</Grid>
</ui:AutoGridEx>
</ui:FluentWindowEx>

View File

@@ -0,0 +1,17 @@
using System.Windows;
namespace ShrlAlgo.RvKits.RvFamily
{
/// <summary>
/// RenameFamilyView.xaml 的交互逻辑
/// </summary>
public partial class RenameFamilyView
{
public RenameFamilyView(RvFamily.RenameFamilyViewModel familyViewModel)
{
DataContext = familyViewModel;
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,323 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
namespace ShrlAlgo.RvKits.RvFamily;
public partial class RenameFamilyViewModel : ObservableObject
{
public RenameFamilyViewModel(UIApplication uiApplication)
{
doc = uiApplication.ActiveUIDocument.Document;
allCategories = GetCategoriesFromDocument();
Collection = allCategories;
//ICollectionView cv = CollectionViewSource.GetDefaultView(Categories);
//cv.Filter = item => string.IsNullOrEmpty(SearchText) ||
// ((KeyValuePair<BuiltInCategory, string>)item).Value.IndexOf(SearchText, StringComparison.OrdinalIgnoreCase) >= 0;
//TaskDialog.Show("数量", CategoriesDictionary.Count.ToString());
}
//[ObservableProperty]
//private List<BuiltInCategory> selectedBuiltInCategories;
private readonly Dictionary<string, List<Family>> allCategories;
//public ICollectionView CategoriesCollectionView { get; set; }
private readonly Document doc;
[ObservableProperty]
private bool canInput;
[ObservableProperty]
private bool isRunning;
[ObservableProperty]
private bool isUsed;
[ObservableProperty]
private Dictionary<string, List<Family>> collection;
[ObservableProperty]
private int categoryCount;
/// <summary>
/// 列表中元素
/// </summary>
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(ModifyNameCommand))]
private List<RenameFamilyItem> renameItems;
[ObservableProperty]
private string foundText;
[ObservableProperty]
private string prefixText;
[ObservableProperty]
private string replaceText;
[ObservableProperty]
private string searchText;
[ObservableProperty]
private string separator = "-";
[ObservableProperty]
private string suffixText;
// ReSharper disable once ConditionIsAlwaysTrueOrFalse
public bool CanModify => RenameItems?.Any(item => item.IsSelected) == true;
public bool? IsAllItemsSelected
{
get
{
if (RenameItems == null)
{
return false;
}
var selected = RenameItems.Select(item => item.IsSelected).Distinct().ToList();
return selected?.Count == 1 ? selected.Single() : null;
}
set
{
if (value.HasValue)
{
SelectAll(value.Value, RenameItems);
OnPropertyChanged();
}
}
}
partial void OnIsUsedChanged(bool value)
{
if (value)
{
var collector = doc.OfCollector().WhereElementIsNotElementType();
foreach (var item in RenameItems)
{
foreach (var id in item.Family.GetFamilySymbolIds())
{
var b = collector.Any(e => e.GetTypeId() == id);
if (b)
{
item.IsSelected = true;
break;
}
}
}
}
}
public Dictionary<string, List<Family>> GetCategoriesFromDocument()
{
var dict = new FilteredElementCollector(doc)
.OfClass(typeof(Family))
.Cast<Family>()
.Where(f => f.FamilyCategory is { CategoryType: CategoryType.Model or CategoryType.Annotation, AllowsBoundParameters: true })
.GroupBy(f => f.FamilyCategory.Id)
.ToDictionary(g => Category.GetCategory(doc, g.Key).Name, g => g.ToList());
CategoryCount = dict.Count;
return dict;
//foreach (BuiltInCategory builtInCategory in Enum.GetValues(typeof(BuiltInCategory)))
//{
// Category category = Category.GetCategory(doc, builtInCategory);
// if (category is
// {
// CategoryType: CategoryType.Model or CategoryType.Annotation,
// AllowsBoundParameters: true
// })
// {
// var familyType = new FilteredElementCollector(doc)
// .QueryElementsByType(typeof(Family))
// .OfCategory(builtInCategory)
// .Cast<Family>()
// .ToList();
// if (familyType.Any())
// {
// var name = category.Name;
// items.Add(builtInCategory, name);
// }
// }
//}
//CategoryCount = items.Count;
//return items.OrderBy(kv => kv.Value).ToDictionary(kv => kv.Key, kv => kv.Value);
}
[RelayCommand(CanExecute = nameof(CanModify))]
private async Task ModifyName()
{
await Task.Delay(1_000);
ModifyFamilyName();
}
/// <summary>
/// 获取列表中所有条目的新名称
/// </summary>
private void GetNewNames()
{
var selectedItems = RenameItems.Where(item => item.IsSelected);
foreach (var renameItem in selectedItems)
{
var tempName = renameItem.OldFamilyName;
//手动修改的新名称不处理
if (!string.IsNullOrEmpty(renameItem.NewFamilyName))
{
continue;
}
if (!string.IsNullOrEmpty(FoundText))
{
tempName = tempName.Replace(FoundText, string.IsNullOrEmpty(ReplaceText) ? string.Empty : ReplaceText);
}
if (!string.IsNullOrEmpty(PrefixText))
{
tempName = tempName.Insert(0, $"{PrefixText}{Separator}");
}
if (!string.IsNullOrEmpty(SuffixText))
{
tempName += $"{Separator}{SuffixText}";
}
renameItem.NewFamilyName = tempName;
}
}
/// <summary>
/// 获取重命名的条目
/// </summary>
/// <param name="items"></param>
[RelayCommand]
private void GetRenameItems(IList items)
{
if (items.Count == 0)
{
RenameItems = null!;
CanInput = false;
return;
}
List<RenameFamilyItem> familyItems = new();
foreach (var item in items)
{
if (item is KeyValuePair<string, List<Family>> categoryItems)
{
//var familyType = new FilteredElementCollector(doc)
// .QueryElementsByType(typeof(Family))
// .Cast<Family>()
// .Where(
// f => f.FamilyCategory.Id.IntegerValue == new ElementId(categoryItem.Key).IntegerValue
// );
foreach (var family in categoryItems.Value)
{
RenameFamilyItem renameItem =
new()
{
OldFamilyName = family.Name,
Family = family,
CategoryName = categoryItems.Key
};
familyItems.Add(renameItem);
}
}
}
CanInput = familyItems.Any();
RenameItems = familyItems;
//IsAllItemsSelected = true;
foreach (var renameItem in RenameItems)
{
renameItem.PropertyChanged += (sender, args) =>
{
//选中属性修改时,触发
if (args.PropertyName == nameof(RenameFamilyItem.IsSelected))
{
OnPropertyChanged(nameof(IsAllItemsSelected));
ModifyNameCommand.NotifyCanExecuteChanged();
if (string.IsNullOrEmpty(renameItem.NewFamilyName))
{
GetNewNames();
}
}
//单个修改名称时
//if (args.PropertyName == nameof(RenameFamilyItem.NewFamilyName))
//{
// ModifyFamilyName();
//}
};
}
}
/// <summary>
/// 修改族名称
/// </summary>
private void ModifyFamilyName()
{
var needToRename = RenameItems.Where(item => item.IsSelected);
using Transaction ts = new(doc, "修改族名称");
ts.Start();
foreach (var renameItem in needToRename)
{
if (!string.IsNullOrEmpty(renameItem.NewFamilyName))
{
renameItem.Family.Name = renameItem.NewFamilyName;
renameItem.OldFamilyName = renameItem.NewFamilyName;
}
}
ts.Commit();
}
partial void OnFoundTextChanged(string value)
{
GetNewNames();
}
partial void OnPrefixTextChanged(string value)
{
GetNewNames();
}
partial void OnReplaceTextChanged(string value)
{
GetNewNames();
}
partial void OnSearchTextChanged(string value)
{
Collection = allCategories
.Where(kv => string.IsNullOrEmpty(value) || kv.Key.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0)
.ToDictionary(k => k.Key, v => v.Value);
CategoryCount = Collection.Count;
//CategoriesCollectionView.Refresh();
}
partial void OnSeparatorChanged(string value)
{
GetNewNames();
}
partial void OnSuffixTextChanged(string value)
{
GetNewNames();
}
private static void SelectAll(bool select, IEnumerable<RenameFamilyItem> models)
{
foreach (var model in models)
{
model.IsSelected = select;
}
}
}

View File

@@ -0,0 +1,42 @@
using Autodesk.Revit.DB;
using CommunityToolkit.Mvvm.ComponentModel;
using ShrlAlgo.Toolkit.Mvvm.Attributes;
namespace ShrlAlgo.RvKits.RvFamily;
public partial class RenameTypeItem : ObservableValidator
{
[ObservableProperty]
private bool isSelected;
[ObservableProperty]
[UndefinedChar]
[NotifyDataErrorInfo]
private string newTypeName;
[ObservableProperty]
private string oldTypeName;
partial void OnIsSelectedChanged(bool value)
{
if (value == false)
{
NewTypeName = string.Empty;
}
}
public ElementType ElementType { get; set; }
public string CategoryName { get; set; }
public string FamilyName { get; set; }
//public RenameTypeItem()
//{
// PropertyChanged += (sender, args) =>
// {
// if (args.PropertyName == nameof(RenameTypeItem.IsSelected))
// OnPropertyChanged(nameof(RenameTypeViewModel.IsAllItemsSelected));
// };
//}
}

View File

@@ -0,0 +1,28 @@
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Nice3point.Revit.Toolkit.External;
using System;
using System.Windows;
namespace ShrlAlgo.RvKits.RvFamily
{
/// <summary>
/// Revit执行命令
/// </summary>
[Transaction(TransactionMode.Manual)]
[Regeneration(RegenerationOption.Manual)]
public class RenameTypeNameCmd : ExternalCommand
{
public override void Execute()
{
RenameTypeViewModel viewmodel = new(UiApplication);
RenameTypeView win = new(viewmodel);
win.ShowDialog();
}
}
}

View File

@@ -0,0 +1,252 @@
<ui:FluentWindowEx
x:Class="ShrlAlgo.RvKits.RvFamily.RenameTypeView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ShrlAlgo.RvKits.RvFamily"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="https://github.com/ShrlAlgo/WPFluent"
xmlns:attachedProps="clr-namespace:ShrlAlgo.Toolkit.Mvvm.AttachedProps"
xmlns:validationRules="clr-namespace:ShrlAlgo.Toolkit.Mvvm.ValidationRules"
Title="重命名族类型"
Width="900"
Height="600"
d:DataContext="{d:DesignInstance local:RenameTypeViewModel}"
mc:Ignorable="d">
<Window.Resources>
<ResourceDictionary Source="pack://application:,,,/ShrlAlgo.RvKits;component/WPFUI.xaml" />
</Window.Resources>
<ui:AutoGridEx
ChildMargin="5"
Columns="250,*,*,*"
Rows="*,Auto">
<ui:AutoGridEx
Grid.RowSpan="2"
Columns="*"
Rows="*,Auto,Auto">
<GroupBox Header="族类别">
<ListBox
x:Name="LbCategories"
d:ItemsSource="{d:SampleData ItemCount=5}"
DisplayMemberPath="Key"
ItemsSource="{Binding Collection, Mode=OneWay}"
SelectionMode="Multiple">
<b:Interaction.Triggers>
<b:EventTrigger EventName="SelectionChanged">
<b:InvokeCommandAction Command="{Binding GetRenameItemsCommand}" CommandParameter="{Binding SelectedItems, RelativeSource={RelativeSource AncestorType={x:Type ListBox}, Mode=FindAncestor}}" />
</b:EventTrigger>
</b:Interaction.Triggers>
<!--<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<ui:VirtualizingWrapPanel />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>-->
<!--<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType=ListBoxItem}}" />
<TextBlock VerticalAlignment="Center" Text="{Binding Value}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>-->
</ListBox>
</GroupBox>
<DockPanel Margin="5,503,5,40">
<CheckBox Content="全选" DockPanel.Dock="Left">
<b:Interaction.Triggers>
<b:EventTrigger EventName="Checked">
<b:CallMethodAction MethodName="SelectAll" TargetObject="{Binding ElementName=LbCategories}" />
</b:EventTrigger>
<b:EventTrigger EventName="Unchecked">
<b:CallMethodAction MethodName="UnselectAll" TargetObject="{Binding ElementName=LbCategories}" />
</b:EventTrigger>
</b:Interaction.Triggers>
</CheckBox>
<TextBlock
HorizontalAlignment="Right"
VerticalAlignment="Center"
DockPanel.Dock="Right"
Text="{Binding CategoryCount, StringFormat=类别个数:\{0:D\}}" />
</DockPanel>
<ui:TextBox
Margin="5,535,5,5"
PlaceholderText="过滤族类别"
Text="{Binding SearchText, UpdateSourceTrigger=PropertyChanged}" />
</ui:AutoGridEx>
<DataGrid
Grid.Row="0"
Grid.Column="1"
Grid.ColumnSpan="3"
attachedProps:TextSearch.SearchValue="{Binding Text, ElementName=TbFound, UpdateSourceTrigger=PropertyChanged}"
AutoGenerateColumns="False"
CanUserAddRows="False"
HeadersVisibility="Column"
ItemsSource="{Binding RenameItems}"
SelectionMode="Extended"
SelectionUnit="Cell">
<DataGrid.Resources>
<Style BasedOn="{StaticResource DefaultDataGridCellStyle}" TargetType="{x:Type DataGridCell}">
<Setter Property="attachedProps:TextSearch.IsTextMatch">
<Setter.Value>
<MultiBinding Converter="{StaticResource SearchTypeValueConverter}">
<Binding Path="Content.Text" RelativeSource="{RelativeSource Mode=Self}" />
<Binding Path="(attachedProps:TextSearch.SearchValue)" RelativeSource="{RelativeSource Mode=Self}" />
<Binding RelativeSource="{RelativeSource Mode=Self}" />
</MultiBinding>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="attachedProps:TextSearch.IsTextMatch" Value="True">
<Setter Property="Foreground" Value="SkyBlue" />
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.Resources>
<DataGrid.ColumnHeaderStyle>
<Style BasedOn="{StaticResource DefaultDataGridColumnHeaderStyle}" TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
</Style>
</DataGrid.ColumnHeaderStyle>
<DataGrid.Columns>
<DataGridCheckBoxColumn
Binding="{Binding IsSelected, UpdateSourceTrigger=PropertyChanged}"
EditingElementStyle="{StaticResource DataGridCheckBoxEditingElementDefaultStyle}"
ElementStyle="{StaticResource DataGridCheckBoxElementDefaultStyle}">
<DataGridCheckBoxColumn.Header>
<CheckBox
HorizontalAlignment="Center"
Content="全选"
IsChecked="{Binding DataContext.IsAllItemsSelected, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />
</DataGridCheckBoxColumn.Header>
</DataGridCheckBoxColumn>
<DataGridTextColumn
MinWidth="80"
Binding="{Binding CategoryName}"
Header="族类别"
IsReadOnly="True">
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn
MinWidth="80"
Binding="{Binding FamilyName}"
Header="族名称"
IsReadOnly="True">
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn
MinWidth="80"
Binding="{Binding OldTypeName}"
Header="族类型"
IsReadOnly="True">
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn
MinWidth="80"
Binding="{Binding NewTypeName, UpdateSourceTrigger=PropertyChanged}"
EditingElementStyle="{StaticResource DefaultTextBoxStyle}"
Header="新族类型名称">
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
<GroupBox Header="前/后缀">
<UniformGrid Columns="1">
<ui:TextBox
Margin="5"
IsEnabled="{Binding CanInput}"
PlaceholderText="前缀">
<Binding Path="PrefixText" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<validationRules:UndefinedCharRules ValidatesOnTargetUpdated="True" />
</Binding.ValidationRules>
</Binding>
</ui:TextBox>
<ui:TextBox
Margin="5"
IsEnabled="{Binding CanInput}"
PlaceholderText="后缀">
<Binding Path="SuffixText" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<validationRules:UndefinedCharRules ValidatesOnTargetUpdated="True" />
</Binding.ValidationRules>
</Binding>
</ui:TextBox>
</UniformGrid>
</GroupBox>
<GroupBox Header="查找/替换">
<UniformGrid Columns="1">
<ui:TextBox
x:Name="TbFound"
Margin="5"
IsEnabled="{Binding CanInput}"
PlaceholderText="查找">
<Binding Path="FoundText" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<validationRules:UndefinedCharRules ValidatesOnTargetUpdated="True" />
</Binding.ValidationRules>
</Binding>
</ui:TextBox>
<ui:TextBox
x:Name="TbReplace"
Margin="5"
IsEnabled="{Binding CanInput}"
PlaceholderText="替换">
<Binding Path="ReplaceText" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<validationRules:UndefinedCharRules ValidatesOnTargetUpdated="True" />
</Binding.ValidationRules>
</Binding>
</ui:TextBox>
</UniformGrid>
</GroupBox>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<GroupBox Grid.Row="0" Header="分隔符">
<TextBox x:Name="TbSeparator" IsEnabled="{Binding CanInput}">
<Binding Path="Separator" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<validationRules:UndefinedCharRules ValidatesOnTargetUpdated="True" />
</Binding.ValidationRules>
</Binding>
</TextBox>
</GroupBox>
<!--
materialDesign:ButtonProgressAssist.IsIndeterminate="{Binding ModifyNameCommand.IsRunning, Mode=OneWay}"
materialDesign:ButtonProgressAssist.IsIndicatorVisible="{Binding ModifyNameCommand.IsRunning, Mode=OneWay}"
materialDesign:ButtonProgressAssist.Value="-1"
-->
<ui:Button
Grid.Row="1"
HorizontalAlignment="Stretch"
Command="{Binding ModifyNameCommand}"
Content="修改名称"
ToolTip="勾选要修改的项进行修改" />
</Grid>
</ui:AutoGridEx>
</ui:FluentWindowEx>

View File

@@ -0,0 +1,16 @@
using System.Windows;
namespace ShrlAlgo.RvKits.RvFamily
{
/// <summary>
/// RenameFamilyView.xaml 的交互逻辑
/// </summary>
public partial class RenameTypeView
{
public RenameTypeView(RenameTypeViewModel typeViewModel)
{
DataContext = typeViewModel;
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,306 @@
using System.Collections;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
namespace ShrlAlgo.RvKits.RvFamily;
public partial class RenameTypeViewModel : ObservableObject
{
public RenameTypeViewModel(UIApplication uiApplication)
{
doc = uiApplication.ActiveUIDocument.Document;
allCategories = GetCategoriesFromDocument();
Collection = allCategories;
//ICollectionView cv = CollectionViewSource.GetDefaultView(Categories);
//cv.Filter = item => string.IsNullOrEmpty(SearchText) ||
// ((KeyValuePair<BuiltInCategory, string>)item).Value.IndexOf(SearchText, StringComparison.OrdinalIgnoreCase) >= 0;
//TaskDialog.Show("数量", CategoriesDictionary.Count.ToString());
}
//[ObservableProperty]
//private List<BuiltInCategory> selectedBuiltInCategories;
private readonly Dictionary<string, List<ElementType>> allCategories;
//public ICollectionView CategoriesCollectionView { get; set; }
private readonly Document doc;
/// <summary>
/// 列表中元素
/// </summary>
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(ModifyNameCommand))]
//[NotifyPropertyChangedFor(nameof(IsAllItemsSelected))]
private List<RenameTypeItem> renameItems;
[ObservableProperty]
private bool canInput;
[ObservableProperty]
private bool isRunning;
/// <summary>
/// 选中正在使用中的条目
/// </summary>
[ObservableProperty]
private bool isUsed;
[ObservableProperty]
private Dictionary<string, List<ElementType>> collection;
[ObservableProperty]
private int categoryCount;
[ObservableProperty]
private int modifyType;
[ObservableProperty]
private string foundText;
[ObservableProperty]
private string prefixText;
[ObservableProperty]
private string replaceText;
[ObservableProperty]
private string searchText;
[ObservableProperty]
private string separator = "-";
[ObservableProperty]
private string suffixText;
//[ObservableProperty]
//private IList selectedItems;
// ReSharper disable once ConditionIsAlwaysTrueOrFalse
public bool CanModify => RenameItems != null && RenameItems.Any(item => item.IsSelected);
//[ObservableProperty]
//private bool? isAllItemsSelected;
//partial void OnIsAllItemsSelectedChanged(bool? value)
//{
// if (value.HasValue)
// {
// SelectAll(value.Value, RenameItems);
// }
//}
public bool? IsAllItemsSelected
{
get
{
if (RenameItems == null)
{
return false;
}
var selected = RenameItems?.Select(item => item.IsSelected).Distinct().ToList();
return selected?.Count == 1 ? selected.Single() : null;
}
set
{
if (value.HasValue)
{
SelectAll(value.Value, RenameItems);
OnPropertyChanged();
}
}
}
public Dictionary<string, List<ElementType>> GetCategoriesFromDocument()
{
var dict = new FilteredElementCollector(doc)
.OfClass(typeof(ElementType))
.Cast<ElementType>()
.Where(t => t.CanBeRenamed && t.Category is { CategoryType: CategoryType.Model or CategoryType.Annotation, AllowsBoundParameters: true })
.GroupBy(t => t.Category.Id)
.ToDictionary(g => Category.GetCategory(doc, g.Key).Name, g => g.ToList());
CategoryCount = dict.Count;
return dict;
//foreach (BuiltInCategory builtInCategory in Enum.GetValues(typeof(BuiltInCategory)))
//{
// try
// {
// var types = new FilteredElementCollector(doc).OfCategory(builtInCategory).WhereElementIsElementType().Cast<ElementType>().ToList();
// if (types.Any() && types.Any(t => t.CanBeRenamed))
// {
// var category = types.FirstOrDefault()!.Category;
// if (category is { CategoryType: CategoryType.Model or CategoryType.Annotation, AllowsBoundParameters: true })
// {
// var name = category.Name;
// items.Add(builtInCategory, name);
// }
// }
// }
// catch (Exception)
// {
// //string name = Enum.GetName(typeof(BuiltInCategory), builtInCategory);
// //TaskDialog.Show( "错误", $"{name}");
// }
//}
//CategoryCount = items.Count;
//return items.OrderBy(kv => kv.Value).ToDictionary(kv => kv.Key, kv => kv.Value);
}
[RelayCommand(CanExecute = nameof(CanModify))]
private async Task ModifyName()
{
await Task.Delay(1_000);
ModifyTypeName();
}
/// <summary>
/// 获取列表中所有条目的新名称
/// </summary>
private void GetNewNames()
{
var selectedItems = RenameItems.Where(item => item.IsSelected);
foreach (var renameItem in selectedItems)
{
var tempName = renameItem.OldTypeName;
////手动修改的新名称不处理
//if (!string.IsNullOrEmpty(renameItem.NewTypeName))
//{
// continue;
//}
if (!string.IsNullOrEmpty(FoundText))
{
tempName = tempName.Replace(FoundText, string.IsNullOrEmpty(ReplaceText) ? string.Empty : ReplaceText);
}
if (!string.IsNullOrEmpty(PrefixText))
{
tempName = tempName.Insert(0, $"{PrefixText}{Separator}");
}
if (!string.IsNullOrEmpty(SuffixText))
{
tempName += $"{Separator}{SuffixText}";
}
renameItem.NewTypeName = tempName;
}
}
[RelayCommand]
private void GetRenameItems(IList items)
{
if (items.Count == 0)
{
RenameItems = null!;
CanInput = false;
return;
}
List<RenameTypeItem> symbolItems = [];
foreach (var item in items)
{
if (item is KeyValuePair<string, List<ElementType>> categoryItems)
{
foreach (var type in categoryItems.Value)
{
RenameTypeItem renameItem = new()
{
OldTypeName = type.Name,
ElementType = type,
CategoryName = categoryItems.Key,
FamilyName = type.FamilyName
};
symbolItems.Add(renameItem);
}
}
}
CanInput = symbolItems.Count > 0;
RenameItems = symbolItems;
foreach (var renameItem in RenameItems)
{
renameItem.PropertyChanged += (_, args) =>
{
if (args.PropertyName == nameof(RenameTypeItem.IsSelected))
{
OnPropertyChanged(nameof(IsAllItemsSelected));
//foreach (RenameTypeItem item in SelectedItems)
//{
// item.IsSelected = renameItem.IsSelected;
//}
ModifyNameCommand.NotifyCanExecuteChanged();
if (string.IsNullOrEmpty(renameItem.NewTypeName))
{
GetNewNames();
}
}
//if (args.PropertyName == nameof(RenameTypeItem.NewTypeName))
//{
// ModifyTypeName();
//}
};
}
//IsAllItemsSelected = true;
}
private void ModifyTypeName()
{
var needToRename = RenameItems.Where(item => item.IsSelected);
using Transaction ts = new(doc, "修改类型名称");
ts.Start();
foreach (var renameItem in needToRename)
{
if (!string.IsNullOrEmpty(renameItem.NewTypeName))
{
renameItem.ElementType.Name = renameItem.NewTypeName;
renameItem.OldTypeName = renameItem.NewTypeName;
}
}
ts.Commit();
}
partial void OnFoundTextChanged(string value)
{
GetNewNames();
}
partial void OnPrefixTextChanged(string value)
{
GetNewNames();
}
partial void OnReplaceTextChanged(string value)
{
GetNewNames();
}
partial void OnSearchTextChanged(string value)
{
Collection = allCategories.Where(kv => string.IsNullOrEmpty(value) || kv.Key.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0)
.ToDictionary(k => k.Key, v => v.Value);
CategoryCount = Collection.Count;
//CategoriesCollectionView.Refresh();
}
partial void OnSeparatorChanged(string value)
{
GetNewNames();
}
partial void OnSuffixTextChanged(string value)
{
GetNewNames();
}
private static void SelectAll(bool select, IEnumerable<RenameTypeItem> models)
{
foreach (var model in models)
{
model.IsSelected = select;
}
}
}

View File

@@ -0,0 +1,136 @@
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Structure;
using Autodesk.Revit.UI;
using Nice3point.Revit.Toolkit.External;
namespace ShrlAlgo.RvKits.RvFamily;
/// <summary>
/// 替换族实例
/// </summary>
[Transaction(TransactionMode.Manual)]
[Regeneration(RegenerationOption.Manual)]
public class ReplaceInstanceCmd : ExternalCommand
{
public override void Execute()
{
var elementIds = new List<ElementId>();
if (
UiDocument.SelectObject(
new FuncFilter(
e =>
e is FamilyInstance instance
&& instance.Symbol.Family.FamilyPlacementType is FamilyPlacementType.OneLevelBased or FamilyPlacementType.WorkPlaneBased or FamilyPlacementType.TwoLevelsBased
),
"请选择目标族实例"
)
is not FamilyInstance instanceToMatch
)
{
Result = Result.Cancelled;
return;
}
var instancesReplace = UiDocument.SelectObjects(
new FuncFilter(e => e is FamilyInstance instance && instance.Id != instanceToMatch.Id),
"请选择被替换(修改)的族实例"
).Cast<FamilyInstance>();
if (!instancesReplace.Any())
{
Result = Result.Cancelled;
return;
}
Document.Invoke(
_ =>
{
instanceToMatch.Symbol.Activate();
foreach (var instanceReplace in instancesReplace)
{
//跳过相同的实例
if (instanceReplace.Id == instanceToMatch.Id)
{
continue;
}
var p1 = instanceReplace.GetLocXYZ();
var p2 = instanceReplace.HandOrientation;
//默认当前平面视图标高
var level = Document.ActiveView.GenLevel;
var placementType = instanceToMatch.Symbol.Family.FamilyPlacementType;
FamilyInstance newInstance = null;
switch (placementType)
{
case FamilyPlacementType.OneLevelBased:
{
newInstance = Document.Create.NewFamilyInstance(
p1,
instanceToMatch.Symbol,
level,
StructuralType.NonStructural
);
}
break;
case FamilyPlacementType.TwoLevelsBased:
{
level = Document.GetElement(instanceToMatch.LevelId) as Level;
newInstance = Document.Create.NewFamilyInstance(
p1,
instanceToMatch.Symbol,
level,
StructuralType.NonStructural
);
}
break;
case FamilyPlacementType.WorkPlaneBased:
{
newInstance = Document.Create.NewFamilyInstance(
level.GetPlaneReference(),
p1,
p2,
instanceToMatch.Symbol
);
}
break;
default:
break;
}
foreach (Parameter paramSource in instanceReplace.Parameters)
{
//var defini = paramSource.Definition as InternalDefinition;
var b =
paramSource.Definition is InternalDefinition definition
&& (
definition.BuiltInParameter != BuiltInParameter.INVALID
&& definition.BuiltInParameter != BuiltInParameter.DOOR_NUMBER
&& definition.BuiltInParameter != BuiltInParameter.ALL_MODEL_INSTANCE_COMMENTS
);
if (b || paramSource.IsReadOnly || !paramSource.HasValue)
{
continue;
}
foreach (Parameter paramToWrite in newInstance.Parameters)
{
if (paramSource.Definition.Name == paramToWrite.Definition.Name)
{
paramToWrite.SetValue(paramSource.GetValue());
}
}
Document.Regenerate();
}
elementIds.Add(instanceReplace.Id);
}
Document.Delete(elementIds);
},
"替换族实例"
);
}
}

View File

@@ -0,0 +1,330 @@
using System.IO;
using System.Text.RegularExpressions;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Microsoft.Win32;
using Nice3point.Revit.Toolkit.External;
using ShrlAlgo.RvKits.Windows;
using WPFluent.Controls;
using TaskDialog = Autodesk.Revit.UI.TaskDialog;
namespace ShrlAlgo.RvKits.RvFamily;
[Transaction(TransactionMode.Manual)]
[Regeneration(RegenerationOption.Manual)]
public class UpgradeFamilyCmd : ExternalCommand
{
private List<string> fileNames;
public override void Execute()
{
try
{
fileNames = GetSelectedFileNames();
if (fileNames.Count > 0)
{
var progressMonitorViewModel = new ProgressBarManager<string>(UiDocument, fileNames, UpdateFile, "更新文件");
progressMonitorViewModel.ProgressModal();
}
}
catch (Exception e)
{
if (e is not Autodesk.Revit.Exceptions.OperationCanceledException)
{
ErrorMessage = e.Message;
Result = Result.Failed;
}
}
}
/// <summary>
/// 获取选择全路径文件名列表
/// </summary>
private static List<string> GetSelectedFileNames()
{
var taskDialog = new TaskDialog("选择方式")
{
MainInstruction = "选择方式",
MainContent = "请选择方式"
//FooterText = "<a href=\"http://usa.autodesk.com/adsk/servlet/index?siteID=123112&id=2484975 \">"
//+ "进入revit开发中心</a>"
};
taskDialog.AddCommandLink(TaskDialogCommandLinkId.CommandLink1, "选择文件");
taskDialog.AddCommandLink(TaskDialogCommandLinkId.CommandLink2, "选择文件夹");
var tResult = taskDialog.Show();
var list = new List<string>();
switch (tResult)
{
case TaskDialogResult.CommandLink1:
{
var filter = "族文件|*.rfa";
var openFile = new OpenFileDialog
{
Multiselect = true,
Filter = filter
};
openFile.ShowDialog();
if (openFile.FileNames.Length != 0)
{
var strFiles = openFile.FileNames;
foreach (var file in strFiles)
{
list.Add(file);
}
}
break;
}
case TaskDialogResult.CommandLink2:
{
var dialog = new VistaFolderBrowserDialog
{
Multiselect = false
};
dialog.ShowDialog();
if (dialog.SelectedPath != null)
{
var directoryInfo = new DirectoryInfo(dialog.SelectedPath);
var files = directoryInfo.GetFiles("*.rfa", SearchOption.AllDirectories);
foreach (var file in files)
{
list.Add(file.FullName);
}
}
break;
}
}
return list;
}
private void UpdateFile(UIDocument uidoc, string filename, object obj)
{
System.Threading.Thread.Sleep(50);
if (File.GetAttributes(filename).ToString().IndexOf("ReadOnly", StringComparison.Ordinal) != -1)
{
File.SetAttributes(filename, FileAttributes.Normal);
}
Document famdoc;
try
{
famdoc = Application.OpenDocumentFile(filename);
}
catch (Autodesk.Revit.Exceptions.CorruptModelException)
{
return;
}
if (famdoc.IsFamilyDocument)
{
using var trans = new Transaction(famdoc);
trans.Start("删除多余属性值");
var fm = famdoc.FamilyManager;
if (fm.CurrentType == null)
{
var t = Path.GetFileNameWithoutExtension(filename);
fm.NewType(t);
}
try
{
var familyParameter = fm.get_Parameter(BuiltInParameter.ALL_MODEL_URL);
if (familyParameter != null)
{
fm.Set(familyParameter, string.Empty);
}
familyParameter = fm.get_Parameter(BuiltInParameter.ALL_MODEL_TYPE_COMMENTS);
if (familyParameter != null)
{
fm.Set(familyParameter, string.Empty);
}
familyParameter = fm.get_Parameter(BuiltInParameter.ALL_MODEL_DESCRIPTION);
if (familyParameter != null)
{
fm.Set(familyParameter, string.Empty);
}
familyParameter = fm.get_Parameter(BuiltInParameter.KEYNOTE_PARAM);
if (familyParameter != null)
{
fm.Set(familyParameter, string.Empty);
}
familyParameter = fm.get_Parameter(BuiltInParameter.UNIFORMAT_CODE);
if (familyParameter != null)
{
fm.Set(familyParameter, string.Empty);
}
familyParameter = fm.get_Parameter(BuiltInParameter.ALL_MODEL_MODEL);
if (familyParameter != null)
{
fm.Set(familyParameter, string.Empty);
}
var fampara = fm.get_Parameter("族库大师");
if (fampara != null)
{
fm.RemoveParameter(fampara);
}
var hostobjects = new FilteredElementCollector(famdoc)
.OfClass(typeof(HostObject)).ToElementIds();
var rplanes = new FilteredElementCollector(famdoc)
.OfCategory(BuiltInCategory.OST_CLines).ToElementIds();
var dimids = new FilteredElementCollector(famdoc)
.OfClass(typeof(Dimension)).ToElementIds();
var conids = new FilteredElementCollector(famdoc)
.OfClass(typeof(ConnectorElement)).ToElementIds();
//ICollection<ElementId> curids = new FilteredElementCollector(famdoc).OfClass(typeof(CurveElement)).ToElementIds();
var textnotes = new FilteredElementCollector(famdoc)
.OfClass(typeof(TextNote)).ToElementIds();
var lightsources = new FilteredElementCollector(famdoc)
.OfCategory(BuiltInCategory.OST_LightingFixtureSource).ToElementIds();
var lights = new FilteredElementCollector(famdoc)
.OfCategory(BuiltInCategory.OST_LightingFixtures).ToElementIds();
var sketchgrids = new FilteredElementCollector(famdoc)
.OfCategory(BuiltInCategory.OST_IOSSketchGrid).ToElementIds();
var modelcurves = new FilteredElementCollector(famdoc)
.OfCategory(BuiltInCategory.OST_ReferenceLines).ToElementIds();
var facebox =
new FilteredElementCollector(famdoc).OfClass(typeof(Extrusion));
//UiDocument.ActiveView = v3d;
//UIView uIView = UiDocument.GetOpenUIViews().Where(x => x.ViewId == v3d.ViewId).FirstOrDefault();
//uIView.ZoomToFit();
var setting = famdoc.GetDocumentPreviewSettings();
var previewid = famdoc.FindPreviewId<View3D>(setting);
setting.PreviewViewId = previewid;
var v = famdoc.GetElement(previewid) as View;
setting.ForceViewUpdate(true);
//得到基于面的族样板拉伸体
if (facebox.Count() != 0)
{
var boxs = from x in facebox
where Math.Abs(x.get_Parameter(BuiltInParameter.EXTRUSION_END_PARAM).AsDouble() - -1) < 0.0001
select x.Id;
var elementIds = boxs.ToList();
if (elementIds.Count() != 0)
{
v.HideElementsTemporary(elementIds);
}
}
//var graphicDisplayOptions = v3d.get_Parameter(BuiltInParameter.MODEL_GRAPHICS_STYLE);
//graphicDisplayOptions.Set(8);
v.DisplayStyle = DisplayStyle.RealisticWithEdges;
v.DetailLevel = ViewDetailLevel.Fine;
ThinLinesOptions.AreThinLinesEnabled = true;
v.HideElementsTemporary(hostobjects);
v.HideElementsTemporary(rplanes);
v.HideElementsTemporary(dimids);
v.HideElementsTemporary(conids);
v.HideElementsTemporary(textnotes);
v.HideElementsTemporary(lights);
v.HideElementsTemporary(lightsources);
v.HideElementsTemporary(sketchgrids);
v.HideElementsTemporary(modelcurves);
#if REVIT2018 || REVIT2020
var ele = famdoc.GetElement(new ElementId(1537));
#elif REVIT2025
var ele = famdoc.GetElement(ElementId.Parse("1537"));
#endif
if (ele != null)
{
v.HideElementTemporary(ele.Id);
}
if (v is View3D)
{
var v3d = v as View3D;
if (v3d.IsLocked)
{
v3d.Unlock();
}
if (famdoc.OwnerFamily.FamilyCategory ==
Category.GetCategory(famdoc, BuiltInCategory.OST_LightingFixtures))
{
v3d.OrientTo(new XYZ(-1, 1, 1));
}
else
{
//人看向视图的视角向量
//v3d.OrientTo(new XYZ(-1, 1, -1));
v3d.OrientTo(new XYZ(-1, -1, -1));
}
//v3d.OrientTo(new XYZ(1, -1, -1));
}
//XYZ eyeposition = new XYZ();
//XYZ updirection = XYZ.BasisZ;
//XYZ forwarddirection = XYZ.BasisY;
//ViewOrientation3D orientation3D = new ViewOrientation3D(eyeposition,updirection,forwarddirection);
//v3d.SetOrientation(orientation3D);
//UiDocument.RefreshActiveView();
//v3d.ToggleToIsometric();
//System.Windows.Forms.SendKeys.SendWait("TL");
ThinLinesOptions.AreThinLinesEnabled = true;
var sa = new SaveAsOptions
{
OverwriteExistingFile = true,
PreviewViewId = previewid
};
//SetViewSaveOption(famdoc, v3d, sa, setting);
trans.Commit();
famdoc.SaveAs(filename, sa);
famdoc.Close(false);
}
catch (Exception)
{
//if (ex.GetType() == typeof(OperationCanceledException))
//{
// if (trans.HasStarted())
// {
// trans.Commit();
// famdoc.CloseTrigger(false);
// }
// break;
//}
if (trans.HasStarted())
{
trans.Commit();
famdoc.Close(false);
}
}
}
else //不是族文件时
{
var sa = new SaveAsOptions
{
OverwriteExistingFile = true
};
famdoc.SaveAs(filename, sa);
famdoc.Close(false);
}
var isMatch = Regex.IsMatch(filename, ".\\d{4}(.rfa)");
if (isMatch)
{
File.Delete(filename);
}
}
}