레빗 API WPF

WPF로 객체 정보 조회 플러그인 만들기

2024년 10월 11일

1. My First WPF Plug-In

API 스터디를 시작하고 나서 UI를 만들 때 WinForm과 WPF 중 무엇을 사용해야 하나 고민했었는데 WinForm은 더 이상 서비스를 지원하지 않는다고 하여 WPF로 스터디를 진행하기로 결정했습니다. (편하고 직관적인 건 WinForm인 것 같긴 한데…)

그래서 오늘은 WPF를 사용해서 간단한 플러그인을 만들고 어떻게 Revit에서 실행할 수 있는지 기록을 남기려고 합니다.

WPF 플러그인
이미지 1.WPF 샘플, ⓒ디지털디자인포럼

먼저 플러그인의 간단한 기능을 설명하자면 [이미지 1]처럼 프로젝트 내에 존재하는 문(door)들의 객체 ID(고유값)를 리스트 박스에 나열하고 리스트를 선택하면 우측 Show Details 패널에 이름, 타입, ID, 구속 레벨이 나타납니다 

2. VS로 새 프로젝트 만들기

VS 프로젝트 만들기
이미지 2. VS 프로젝트 만들기, ⓒ디지털디자인포럼

비주얼 스튜디오는 2022 버전을 사용했고 새프로젝트 만들기를 통해서 클래스라이브러리(.Net Framework)를 선택합니다.

프로젝트 만들기
이미지 3. VS 프로젝트 만들기, ⓒ디지털디자인포럼

프로젝트의 이름과 생성 위치는 임의로 정할 수 있지만 저는 이름은 MyFirstWPF로 하고 위치는 C드라이브에 생성하겠습니다.

VS 프로젝트 만들기
이미지 4. VS 프로젝트 만들기, ⓒ디지털디자인포럼

프로젝트를 처음 생성하면 [이미지 4]와 같이 나타납니다.

3. Revit API 참조

레빗 API 참조
이미지 5. 레빗 API 참조, ⓒ디지털디자인포럼

비주얼 스튜디오에서 Revit관련된 기능을 사용하려면 API를 참조해야 하는데, 솔루션 탐색기의 참조를 우클릭하고 참초 추가를 클릭해서 RevitAPIUI.dll, RevitAPI.dll 파일을 추가합니다.

(dll파일의 일반적인 위치는 –>  C:\Program Files\Autodesk\Revit 2021 )

레빗 API 참조
이미지 6. 레빗 API 참조, ⓒ디지털디자인포럼

그리고 방금 참조한 dll 파일을 선택하고 로컬복사를 True에서 False로 변경합니다.

4. 기본 코드 세팅

api 코드 작성
이미지 7. 코드 작성, ⓒ디지털디자인포럼

그리고 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
코드 작성
이미지 8. 코드 작성, ⓒ디지털디자인포럼

5. WPF 설정

이제 솔루션 탐색기에서 네임스페이스(MyFirstWPF)를 우클릭해서 추가 WPF를 추가합니다.

WPF 설정
이미지 9. WPF 설정, ⓒ디지털디자인포럼

WPF를 선택하고 이름을 Viewer.xaml로 설정합니다.

WPF 설정
이미지 10. WPF 설정, ⓒ디지털디자인포럼

이렇게 추가하면 [이미지 10]과 같은 창이 뜨는데 User Control를 선택합니다.

WPF 설정
이미지 11. WPF 설정, ⓒ디지털디자인포럼

그리고 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. 코드 작성

코드 기본 설정
이미지 12. 코드 기본 설정, ⓒ디지털디자인포럼

이번에는 Class1.cs에 돌아와서 //여기에 내용입력으로 주석 처리되었던 부분에 아래의 코드를 붙여 넣습니다.

1
2
3
Document doc = commandData.Application.ActiveUIDocument.Document;
Viewer form = new Viewer(doc);
form.ShowDialog();
cs
코드 기본 설정
이미지 13. 코드 기본 설정, ⓒ디지털디자인포럼

7. Addin 파일 생성

이제 마지막으로 addin 파일을 만들기만 하면 됩니다. 솔루션탐색기에서 새항목 추가를 해주고

Addin 파일 생성
이미지 14. Addin 파일 생성, ⓒ디지털디자인포럼

텍스트 파일을 선택하고 이름을 MyFirstWPF.addin으로 지정합니다. (확장자가 txt가 아니라 addin임)

Addin 파일 생성
이미지 15. 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. 실행 파일 위치 설정

실행파일 위치 설정
이미지 16. 실행파일 위치 설정, ⓒ디지털디자인포럼

이제 진짜 마지막으로 속성 창으로 이동해서

실행파일 위치 설정
이미지 17. 실행파일 위치 설정, ⓒ디지털디자인포럼

디버그 탭을 누르고 시작외부 프로그램에 Revit.exe 파일이 설치된 위치를 지정합니다.

실행파일 위치 설정
이미지 18. 실행파일 위치 설정, ⓒ디지털디자인포럼

그리고 빌드 이벤트에서 아래에 있는 코드를 복사해서 붙여 넣기 하고 빌드하면 첫 번째 WPF 플러그인 완성입니다!

아래 코드는 작성한 MyFirstWPF.addin 파일을 Addin/2021(해당 revit버전)폴더에 생성합니다.

1
copy “$(ProjectDir)MyFirstWPF.addin” “%ProgramData%/Autodesk\Revit\Addins
cs

9. 빌드

빌드 후 플러그인 작동 확인
이미지 19. 빌드 후 플러그인 작동 확인, ⓒ디지털디자인포럼

이제 빌드를 하면 Revit이 실행되는데 [이미지 19]과 같은 경고창이 뜨면 Always Load를 눌러줍니다.

빌드 후 플러그인 작동 확인
이미지 20. 빌드 후 플러그인 작동 확인, ⓒ디지털디자인포럼

그리고 Add-Ins 탬에 External Tools에 가면 방금 작성한 플러그인 이름이 뜨는데 실행하면 

최종 결과물
이미지 21. 최종 결과물, ⓒ디지털디자인포럼

[이미지 21]과 같은 창이 뜨고 좌측 리스트에 있는 문의 Ids를 선택하면 해당 객체의 이름, 타입, id, 구속 레벨 값을 확인할 수 있다.


답글 남기기


다음 글 →

관련 포스트

  • Revit API Ribbon Form

    Ribbon탭 만들고 Form 띄우기

  • hello revit

    Hello Revit 창 띄우기