添加项目文件。
This commit is contained in:
16
Sai.RvKits/RvFamily/FamilyLibrary/FamilyLibraryCmd.cs
Normal file
16
Sai.RvKits/RvFamily/FamilyLibrary/FamilyLibraryCmd.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System.Windows;
|
||||
using Autodesk.Revit.Attributes;
|
||||
using Autodesk.Revit.UI;
|
||||
using Nice3point.Revit.Toolkit.External;
|
||||
|
||||
namespace Sai.RvKits.RvFamily.FamilyLibrary;
|
||||
|
||||
[Transaction(TransactionMode.Manual)]
|
||||
[Regeneration(RegenerationOption.Manual)]
|
||||
public class FamilyLibraryCmd : ExternalCommand
|
||||
{
|
||||
public override void Execute()
|
||||
{
|
||||
WinDialogHelper.ShowModeless<FamilyLibraryView>(new FamilyLibraryViewModel());
|
||||
}
|
||||
}
|
||||
315
Sai.RvKits/RvFamily/FamilyLibrary/FamilyLibraryView.xaml
Normal file
315
Sai.RvKits/RvFamily/FamilyLibrary/FamilyLibraryView.xaml
Normal file
@@ -0,0 +1,315 @@
|
||||
<ex:FluentWindowEx
|
||||
x:Class="Sai.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:ex="https://github.com/sherlockforrest/Wpf.Ui.Extend"
|
||||
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
||||
xmlns:local="clr-namespace:Sai.RvKits.RvFamily.FamilyLibrary"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
|
||||
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:,,,/Sai.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=,
|
||||
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="载入"
|
||||
FontFamily="{StaticResource BoxIcons}"
|
||||
ToolTip="将族载入到当前项目" />
|
||||
<Button
|
||||
Command="{Binding DataContext.LocationFamilyFileCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"
|
||||
CommandParameter="{Binding}"
|
||||
Content="浏览"
|
||||
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="载入"
|
||||
FontFamily="{StaticResource BoxIcons}"
|
||||
ToolTip="将族载入到当前项目" />
|
||||
<ui:Button
|
||||
Appearance="Primary"
|
||||
Command="{Binding DataContext.LocationFamilyFileCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}, Mode=FindAncestor}}"
|
||||
CommandParameter="{Binding}"
|
||||
Content="定位"
|
||||
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>-->
|
||||
<ex:StackPanelEx
|
||||
Grid.Row="0"
|
||||
Grid.Column="4"
|
||||
Orientation="Horizontal">
|
||||
<ex:ComboBoxEx
|
||||
x:Name="CbbSymbols"
|
||||
ex:StackPanelEx.Fill="Fill"
|
||||
DisplayMemberPath="Name"
|
||||
ItemsSource="{Binding SymbolTypes, Mode=TwoWay}"
|
||||
PlaceholderText="选择族类型"
|
||||
SelectedItem="{Binding SelectedSymbolType, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<Button
|
||||
Grid.Column="1"
|
||||
Margin="5"
|
||||
ex:StackPanelEx.Fill="Auto"
|
||||
Command="{Binding ImportFamilySymbolCommand}"
|
||||
Content=""
|
||||
FontFamily="{StaticResource BoxIcons}"
|
||||
ToolTip="载入类型" />
|
||||
</ex: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>
|
||||
</ex:FluentWindowEx>
|
||||
13
Sai.RvKits/RvFamily/FamilyLibrary/FamilyLibraryView.xaml.cs
Normal file
13
Sai.RvKits/RvFamily/FamilyLibrary/FamilyLibraryView.xaml.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace Sai.RvKits.RvFamily.FamilyLibrary
|
||||
{
|
||||
/// <summary>
|
||||
/// LocalFamily.xaml 的交互逻辑.
|
||||
/// </summary>
|
||||
public partial class FamilyLibraryView
|
||||
{
|
||||
public FamilyLibraryView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
479
Sai.RvKits/RvFamily/FamilyLibrary/FamilyLibraryViewModel.cs
Normal file
479
Sai.RvKits/RvFamily/FamilyLibrary/FamilyLibraryViewModel.cs
Normal file
@@ -0,0 +1,479 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
using Autodesk.Revit.DB;
|
||||
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
using FuzzySharp;
|
||||
|
||||
using Nice3point.Revit.Toolkit.External.Handlers;
|
||||
|
||||
using Wpf.Ui.Extend.Controls;
|
||||
|
||||
using Settings = Sai.RvKits.Properties.Settings;
|
||||
|
||||
namespace Sai.RvKits.RvFamily.FamilyLibrary;
|
||||
|
||||
public partial class FamilyLibraryViewModel : ObservableObject
|
||||
{
|
||||
public FamilyLibraryViewModel()
|
||||
{
|
||||
loadFamilyHandler = new ActionEventHandler();
|
||||
loadFamilySymbolHandler = new ActionEventHandler();
|
||||
#if REVIT2018
|
||||
familyPath = Settings.Default.FamilyPath_2018;
|
||||
#elif REVIT2019
|
||||
familyPath = Settings.Default.FamilyPath_2019;
|
||||
#elif REVIT2020
|
||||
familyPath = Settings.Default.FamilyPath_2020;
|
||||
#elif REVIT2021
|
||||
familyPath = Settings.Default.FamilyPath_2021;
|
||||
#endif
|
||||
PageSize = 20;
|
||||
Initialize();
|
||||
}
|
||||
|
||||
private readonly ActionEventHandler loadFamilyHandler;
|
||||
private readonly ActionEventHandler loadFamilySymbolHandler;
|
||||
|
||||
[ObservableProperty]
|
||||
private string familyPath;
|
||||
|
||||
[ObservableProperty]
|
||||
private int pageCount;
|
||||
|
||||
[ObservableProperty]
|
||||
private int pageSize;
|
||||
|
||||
[ObservableProperty]
|
||||
private string revitVersion;
|
||||
|
||||
[ObservableProperty]
|
||||
private FamilyModel selectedFamily;
|
||||
|
||||
[ObservableProperty]
|
||||
private FamilySymbolType selectedSymbolType;
|
||||
|
||||
[ObservableProperty]
|
||||
private List<FamilySymbolType> symbolTypes;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool activeSnackbar;
|
||||
|
||||
[ObservableProperty]
|
||||
private Wpf.Ui.Controls.InfoBar messageQueue = new();
|
||||
|
||||
[ObservableProperty]
|
||||
private string message;
|
||||
|
||||
partial void OnMessageChanged(string value)
|
||||
{
|
||||
ActiveSnackbar = true;
|
||||
}
|
||||
|
||||
public int FamilyCount => FamilyDataSource.Count;
|
||||
|
||||
/// <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 };
|
||||
|
||||
/* 项目“Sai.RvKits (net481)”的未合并的更改
|
||||
在此之前:
|
||||
SubDirectories(info.GetDirectories(), rootNode);
|
||||
在此之后:
|
||||
FamilyLibraryViewModel.SubDirectories(info.GetDirectories(), rootNode);
|
||||
*/
|
||||
SubDirectories(info.GetDirectories(), rootNode);
|
||||
//dirTree.DataContext = rootNode;
|
||||
FolderTreeViewItems!.Add(rootNode);
|
||||
rootNode.IsExpanded = true;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void SearchFamily(object obj)
|
||||
{
|
||||
//ListViewItem foundItem =
|
||||
// textListView.FindItemWithText(searchBox.Text, false, 0, true);
|
||||
//if (foundItem != null)
|
||||
//{
|
||||
// textListView.TopItem = foundItem;
|
||||
//}
|
||||
//Func<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 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)
|
||||
{
|
||||
/* 项目“Sai.RvKits (net481)”的未合并的更改
|
||||
在此之前:
|
||||
SubDirectories(subSubDirs, aNode);
|
||||
在此之后:
|
||||
FamilyLibraryViewModel.SubDirectories(subSubDirs, aNode);
|
||||
*/
|
||||
SubDirectories(subSubDirs, aNode);
|
||||
}
|
||||
|
||||
nodeToAddTo.Items.Add(aNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
88
Sai.RvKits/RvFamily/FamilyLibrary/FamilyModel.cs
Normal file
88
Sai.RvKits/RvFamily/FamilyLibrary/FamilyModel.cs
Normal file
@@ -0,0 +1,88 @@
|
||||
using System.IO;
|
||||
using System.Windows.Media.Imaging;
|
||||
using Autodesk.Revit.DB;
|
||||
using Autodesk.Revit.UI;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Sai.Toolkit.Core.Extensions;
|
||||
|
||||
namespace Sai.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();
|
||||
}
|
||||
}
|
||||
}
|
||||
17
Sai.RvKits/RvFamily/FamilyLibrary/LoadedFamilyDropHandler.cs
Normal file
17
Sai.RvKits/RvFamily/FamilyLibrary/LoadedFamilyDropHandler.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using Autodesk.Revit.DB;
|
||||
using Autodesk.Revit.UI;
|
||||
|
||||
namespace Sai.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
16
Sai.RvKits/RvFamily/FamilyLibrary/Models.cs
Normal file
16
Sai.RvKits/RvFamily/FamilyLibrary/Models.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
namespace Sai.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; }
|
||||
}
|
||||
}
|
||||
645
Sai.RvKits/RvFamily/FamilyLibrary/RevitFileUtil.cs
Normal file
645
Sai.RvKits/RvFamily/FamilyLibrary/RevitFileUtil.cs
Normal file
@@ -0,0 +1,645 @@
|
||||
using System;
|
||||
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 Sai.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user