WPF로 객체 정보 조회 플러그인 만들기
1. My First WPF Plug-In
API 스터디를 시작하고 나서 UI를 만들 때 WinForm과 WPF 중 무엇을 사용해야 하나 고민했었는데 WinForm은 더 이상 서비스를 지원하지 않는다고 하여 WPF로 스터디를 진행하기로 결정했습니다. (편하고 직관적인 건 WinForm인 것 같긴 한데…)
그래서 오늘은 WPF를 사용해서 간단한 플러그인을 만들고 어떻게 Revit에서 실행할 수 있는지 기록을 남기려고 합니다.
먼저 플러그인의 간단한 기능을 설명하자면 [이미지 1]처럼 프로젝트 내에 존재하는 문(door)들의 객체 ID(고유값)를 리스트 박스에 나열하고 리스트를 선택하면 우측 Show Details 패널에 이름, 타입, ID, 구속 레벨이 나타납니다
2. VS로 새 프로젝트 만들기
비주얼 스튜디오는 2022 버전을 사용했고 새프로젝트 만들기를 통해서 클래스라이브러리(.Net Framework)를 선택합니다.
프로젝트의 이름과 생성 위치는 임의로 정할 수 있지만 저는 이름은 MyFirstWPF로 하고 위치는 C드라이브에 생성하겠습니다.
프로젝트를 처음 생성하면 [이미지 4]와 같이 나타납니다.
3. Revit API 참조
비주얼 스튜디오에서 Revit관련된 기능을 사용하려면 API를 참조해야 하는데, 솔루션 탐색기의 참조를 우클릭하고 참초 추가를 클릭해서 RevitAPIUI.dll, RevitAPI.dll 파일을 추가합니다.
(dll파일의 일반적인 위치는 –> C:\Program Files\Autodesk\Revit 2021 )
그리고 방금 참조한 dll 파일을 선택하고 로컬복사를 True에서 False로 변경합니다.
4. 기본 코드 세팅
그리고 Class1.cs파일에 아래의 코드를 덮어 씌웁니다. 여기까지가 Revit에서 API를 하기 위한 기본 설정입니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Autodesk.Revit.DB; using Autodesk.Revit.UI; using Autodesk.Revit.Attributes; namespace MyFirstWPF { [Transaction(TransactionMode.Manual)] public class Class1 : IExternalCommand { public Result Execute(ExternalCommandData commandData, ref string message,ElementSet elements) { //여기에 내용입력 return Result.Succeeded; } } } | cs |
5. WPF 설정
이제 솔루션 탐색기에서 네임스페이스(MyFirstWPF)를 우클릭해서 추가 WPF를 추가합니다.
WPF를 선택하고 이름을 Viewer.xaml로 설정합니다.
이렇게 추가하면 [이미지 10]과 같은 창이 뜨는데 User Control를 선택합니다.
그리고 Window로 바꾸면 [이미지 11] 처럼 UI창을 볼 수 있습니다.
WPF를 구성하는 방법은 추후에 다시 다루도록 하고 Viewer.xaml에 아래의 코드를 덮어씁니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | <Window x:Class=“MyFirstWPF.Viewer” xmlns=“http://schemas.microsoft.com/winfx/2006/xaml/presentation” xmlns:x=“http://schemas.microsoft.com/winfx/2006/xaml” xmlns:mc=“http://schemas.openxmlformats.org/markup-compatibility/2006” xmlns:d=“http://schemas.microsoft.com/expression/blend/2008” xmlns:local=“clr-namespace:MyFirstWPF” mc:Ignorable=“d” Height=“415” Width=“600” Title=“My First WPF Sample” WindowStartupLocation=“CenterScreen” ResizeMode=“NoResize”> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width=“*”/> <ColumnDefinition Width=“1.5*”/> </Grid.ColumnDefinitions> <GroupBox Grid.Column=“0” Header=“배치된 Door IDs” FontSize=” 15″ Foreground=“Gray” Margin=“5 5 5 5”> <StackPanel> <ListBox Name=“listview” Grid.Row=“0” Height=“320” Margin=“10 10 10 10” SelectionChanged=“listview_SelectionChanged” /> </StackPanel> </GroupBox> <GroupBox Grid.Column=“1” Header=“Show Details” FontSize=” 15″ Foreground=“Gray” Margin=“5 5 5 5”> <StackPanel Margin=” 10,10,10,10″ > <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width=“3*”/> <ColumnDefinition Width=“0.5*”/> <ColumnDefinition Width=“5*”/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height=“50”/> <RowDefinition Height=“50”/> <RowDefinition Height=“50”/> <RowDefinition Height=“50”/> </Grid.RowDefinitions> <TextBlock Grid.Column=“0” Grid.Row=“0” VerticalAlignment=“Center” Text=“Family Name”/> <TextBlock Grid.Column=“0” Grid.Row=“1” VerticalAlignment=“Center” Text=“Family Type”/> <TextBlock Grid.Column=“0” Grid.Row=“2” VerticalAlignment=“Center” Text=“Family ID”/> <TextBlock Grid.Column=“0” Grid.Row=“3” VerticalAlignment=“Center” Text=“Base Level”/> <TextBlock Grid.Column=“1” Grid.Row=“0” VerticalAlignment=“Center” HorizontalAlignment=“Center” Text=” : “/> <TextBlock Grid.Column=“1” Grid.Row=“1” VerticalAlignment=“Center” HorizontalAlignment=“Center” Text=” : “/> <TextBlock Grid.Column=“1” Grid.Row=“2” VerticalAlignment=“Center” HorizontalAlignment=“Center” Text=” : “/> <TextBlock Grid.Column=“1” Grid.Row=“3” VerticalAlignment=“Center” HorizontalAlignment=“Center” Text=” : “/> <TextBlock Name=“name” Grid.Column=“2” Grid.Row=“0” VerticalAlignment=“Center” Text=“-“/> <TextBlock Name=“type” Grid.Column=“2” Grid.Row=“1” VerticalAlignment=“Center” Text=“-“/> <TextBlock Name=“id” Grid.Column=“2” Grid.Row=“2” VerticalAlignment=“Center” Text=“-“/> <TextBlock Name=“level” Grid.Column=“2” Grid.Row=“3” VerticalAlignment=“Center” Text=“-“/> </Grid> </StackPanel> </GroupBox> </Grid> </Window> | cs |
그리고 Viewer.xaml.cs 에 아래의 코드를 덮어 씌웁니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | using Autodesk.Revit.DB; using Autodesk.Revit.UI; using Autodesk.Revit.Attributes; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace MyFirstWPF { /// <summary> /// Interaction logic for Viewer.xaml /// </summary> public partial class Viewer : Window { // field public Document document; // constructor public Viewer(Document doc) { document = doc; InitializeComponent(); DoorFamilyID(); } public void DoorFamilyID() { FilteredElementCollector collector = new FilteredElementCollector(document); ICollection<Element> collection = collector.OfCategory(BuiltInCategory.OST_Doors).ToElements(); foreach (Element e in collection) { string familyId = e.get_Parameter(BuiltInParameter.ID_PARAM).AsValueString(); //프로젝트에 로드된것들만 리스트업 if (e.Location != null) { listview.Items.Add(familyId); } } } private void listview_SelectionChanged(object sender, SelectionChangedEventArgs e) { FilteredElementCollector collector = new FilteredElementCollector(document); ICollection<Element> collection = collector.OfCategory(BuiltInCategory.OST_Doors).ToElements(); if (listview.SelectedItem != null) { string eId = listview.SelectedItem.ToString(); foreach (Element ele in collection) { if (eId == ele.Id.ToString()) { string familyName = ele.get_Parameter(BuiltInParameter.ELEM_FAMILY_PARAM).AsValueString(); string familyType = ele.get_Parameter(BuiltInParameter.ELEM_TYPE_PARAM).AsValueString(); string familyId = ele.get_Parameter(BuiltInParameter.ID_PARAM).AsValueString(); string familyLevel = ele.get_Parameter(BuiltInParameter.FAMILY_LEVEL_PARAM).AsValueString(); type.Text = familyType; name.Text = familyName; id.Text = familyId; level.Text = familyLevel; } } } } } } | cs |
6. 코드 작성
이번에는 Class1.cs에 돌아와서 //여기에 내용입력으로 주석 처리되었던 부분에 아래의 코드를 붙여 넣습니다.
1 2 3 | Document doc = commandData.Application.ActiveUIDocument.Document; Viewer form = new Viewer(doc); form.ShowDialog(); | cs |
7. Addin 파일 생성
이제 마지막으로 addin 파일을 만들기만 하면 됩니다. 솔루션탐색기에서 새항목 추가를 해주고
텍스트 파일을 선택하고 이름을 MyFirstWPF.addin으로 지정합니다. (확장자가 txt가 아니라 addin임)
MyFirstWPF.addin으로 이동한 다음 아래의 코드를 입력해야 하는데
Assembly 사이에는 dll 파일이 생성된 위치를 추가해주고
AddInId 사이에는 Guid 값을 입력합니다
그리고 FullClassName사이에는 네임클래스명.클래스명을 입력합니다.
1 2 3 4 5 6 7 8 9 10 11 | <?xml version=”1.0″ encoding=”utf-8″ standalone=”no”?> <RevitAddIns> <AddIn Type=”Command”> <Assembly>C:\Users\WPFSample\WPFSample\bin\Debug\WPFSample.dll</Assembly> <AddInId>64C53989-6572-42ED-A2BD-51EC4B1F8950</AddInId> <FullClassName>WPFSample.Class1 </FullClassName> <Text>My First WPF Plun-In</Text> <VendorId>건축코딩</VendorId> <VendorDescription>건축코딩</VendorDescription> </AddIn> </RevitAddIns> | cs |
8. 실행 파일 위치 설정
이제 진짜 마지막으로 속성 창으로 이동해서
디버그 탭을 누르고 시작외부 프로그램에 Revit.exe 파일이 설치된 위치를 지정합니다.
그리고 빌드 이벤트에서 아래에 있는 코드를 복사해서 붙여 넣기 하고 빌드하면 첫 번째 WPF 플러그인 완성입니다!
아래 코드는 작성한 MyFirstWPF.addin 파일을 Addin/2021(해당 revit버전)폴더에 생성합니다.
1 | copy “$(ProjectDir)MyFirstWPF.addin” “%ProgramData%/Autodesk\Revit\Addins | cs |
9. 빌드
이제 빌드를 하면 Revit이 실행되는데 [이미지 19]과 같은 경고창이 뜨면 Always Load를 눌러줍니다.
그리고 Add-Ins 탬에 External Tools에 가면 방금 작성한 플러그인 이름이 뜨는데 실행하면
[이미지 21]과 같은 창이 뜨고 좌측 리스트에 있는 문의 Ids를 선택하면 해당 객체의 이름, 타입, id, 구속 레벨 값을 확인할 수 있다.
← 이전 글
다음 글 →
답글 남기기
댓글을 남기려면 로그인 해야 합니다.