การทำรองรับหลายเวอร์ชัน (Multi-Version)
ปัญหาโลกแตกของคนทำ Revit Plugin คือ “ผู้ใช้งานในบริษัทใช้ Revit คนละเวอร์ชันกัน”
Revit มีการเปลี่ยน API ในทุกๆ ปี (เช่น โค้ดที่รันบน 2024 ได้ อาจจะพังบน 2026) ดังนั้นเราจึงไม่ควรรวมทุกเวอร์ชันไว้ใน TargetFramework เดียวกัน เราต้องแยกร่างออกเป็นโปรเจ็กต์ย่อยๆ หรือใช้ Shared Project
วิธีที่นิยมในปัจจุบันและได้รับการยอมรับระดับสากล จะมี 2 แนวทางหลักครับ
แนวทางที่ 1: ใช้ Shared Project (เก่าแต่ชัวร์)
Section titled “แนวทางที่ 1: ใช้ Shared Project (เก่าแต่ชัวร์)”จุดอ่อนของการสร้างโปรเจ็กต์ RevitToolkit2024, RevitToolkit2025, RevitToolkit2026 แยกกัน คือคุณต้อง Copy-Paste โค้ดซ้ำไปซ้ำมา
วิธีแก้คือเอาโค้ดกลางไปใส่ใน “Shared Project”
- ให้สร้างโปรเจ็กต์แบบ
Shared Projectเปล่าๆ ชื่อRevitToolkit.Shared - ย้ายไฟล์
.csและโค้ดทั้งหมด (XAML, Config) ไปไว้ข้างในนั้น - ในโปรเจ็กต์เวอร์ชันเฉพาะกาล (เช่น 2026) ให้กด Add Reference > Shared Projects > ติ๊กเลือก RevitToolkit.Shared
แค่นี้เวลาคุณแก้โค้ดใน 2024 ก็จะกระเทือนไปถึง 2026 ด้วยทันที!
แนวทางที่ 2: ใช้ Directive #if (สมัยใหม่ และยอดฮิต)
Section titled “แนวทางที่ 2: ใช้ Directive #if (สมัยใหม่ และยอดฮิต)”ถ้าคุณรวบทุกเวอร์ชันไว้ใน .csproj เดียวด้วยแท็ก <TargetFrameworks>net48;net8.0-windows</TargetFrameworks> คุณจะเจอปัญหาบรรทัดแดงเวลา API ของ 2 เวอร์ชันตีกัน
เราจึงใช้ Preprocessor Directives เพื่อบอก Compiler ให้ตัดโค้ดบางส่วนทิ้งตอน Build สำหรับเวอร์ชันนั้นๆ
1. ใส่ตัวแปร Revit เข้าไปใน .csproj
Section titled “1. ใส่ตัวแปร Revit เข้าไปใน .csproj” <!-- ถ้ากำลัง Build ของปี 2027 (ใช้ .NET 10) --> <PropertyGroup Condition="'$(Configuration)' == 'Revit2027'"> <TargetFramework>net10.0-windows</TargetFramework> <DefineConstants>REVIT2027</DefineConstants> </PropertyGroup>
<!-- ถ้ากำลัง Build ของปี 2026 (ใช้ .NET 8) --> <PropertyGroup Condition="'$(Configuration)' == 'Revit2026'"> <TargetFramework>net8.0-windows</TargetFramework> <DefineConstants>REVIT2026</DefineConstants> </PropertyGroup>
<!-- ถ้ากำลัง Build ของปี 2024 (ใช้ .NET 4.8) --> <PropertyGroup Condition="'$(Configuration)' == 'Revit2024'"> <TargetFramework>net48</TargetFramework> <DefineConstants>REVIT2024</DefineConstants> </PropertyGroup>2. ใช้ #if ใน Code (C#)
Section titled “2. ใช้ #if ใน Code (C#)”สมมติว่า Revit API ในปี 2024 ใช้คำสั่ง GetUnit() แต่พอมาปี 2026 เปลี่ยนชื่อเป็น GetElementUnit()
คุณสามารถเขียนไฟล์ .cs เดียวกันให้รองรับ 2 แบบได้:
public double ดึงความยาวคาน(Element beam){#if REVIT2026 // โค้ดบรรทัดนี้จะถูกรวมเข้าไปเฉพาะตอนเราเลือกตลับ Build เป็นของปี 2026 return beam.GetElementUnit();
#elif REVIT2024 // ส่วนนี้จะทำงานก็ต่อเมื่อเราสลับไป Build ตัว 2024 ให้ลูกค้าที่ยังไม่อัปเกรดเครื่อง return beam.GetUnit();
#endif}🔍 เจาะลึกความท้าทายระดับสูง: การย้ายเฟรมเวิร์กและระบบหน่วยวัด (Units Migration)
Section titled “🔍 เจาะลึกความท้าทายระดับสูง: การย้ายเฟรมเวิร์กและระบบหน่วยวัด (Units Migration)”เมื่อนักพัฒนาเริ่มก้าวขึ้นสู่การทำปลั๊กอินรองรับหลายเวอร์ชันพร้อมกัน (Multi-targeting) มีมิติเทคนิคสำคัญ 2 ประการที่มักสร้างความปวดหัวให้กับจูเนียร์เดฟอย่างมาก ซึ่งเราจะมาชำแหละวิเคราะห์แนวทางแก้ไขดังนี้ครับ:
1. การปะทะกันของสถาปัตยกรรม .NET (.NET 4.8 vs .NET 8.0 vs .NET 10.0)
Section titled “1. การปะทะกันของสถาปัตยกรรม .NET (.NET 4.8 vs .NET 8.0 vs .NET 10.0)”นี่คือความเปลี่ยนแปลงครั้งใหญ่ที่สุดในประวัติศาสตร์ของ Revit API:
- Revit 2021 - 2024: ทำงานบนเทคโนโลยีแบบเก่าคือ .NET Framework 4.8
- Revit 2025 - 2026: ก้าวข้ามผ่านสู่ยุคโมเดิร์นบน .NET 8.0
- Revit 2027+: ล้ำหน้าไปอีกขั้นด้วยการย้ายโครงสร้างสู่ .NET 10.0
- ปัญหาทางปฏิบัติ: .NET เวอร์ชันต่างกันมีชุดไลบรารีเบื้องหลังหลายชิ้นไม่เหมือนกัน เช่น ระบบหน้าต่าง WPF หรือการประมวลผล JSON
- ทางออกที่ดีที่สุด: เมื่อเราประกาศใช้
<TargetFrameworks>net48;net8.0-windows;net10.0-windows</TargetFrameworks>ให้เราใช้สัญลักษณ์#if REVIT2024คอยดักจับการเรียกใช้คลาสพิเศษที่ยกเลิกไป หรือใช้ชุดเงื่อนไขการติดตั้ง Reference DLL ในไฟล์.csprojแยกประเภทการอ้างอิงให้ชัดเจนตามบล็อกสวิตช์ Configuration ครับ
2. มหากาพย์การเปลี่ยนผ่านระบบหน่วยวัด (ForgeTypeId vs DisplayUnitType)
Section titled “2. มหากาพย์การเปลี่ยนผ่านระบบหน่วยวัด (ForgeTypeId vs DisplayUnitType)”ใน Revit API ทุกเวอร์ชันหลังบ้านจะคำนวณและเก็บมิติวัตถุ (ระยะทาง, ความสูง, ปริมาตร) เป็นหน่วยวัดสากลคือ “ฟุต (Feet)” เสมอ หากปลั๊กอินต้องการแปลงข้อมูลหน่วยวัดให้กลายเป็นระบบเมตรหรือมิลลิเมตรที่เราใช้กันในแบบก่อสร้างทั่วไป:
- แบบเก่า (Revit 2021 และเก่ากว่า): ใช้รหัสระบบตัวแปรแจกแจง
DisplayUnitTypeเช่น:// วิธีแบบเก่า (Deprecated / ถูกยกเลิกไปแล้วในเวอร์ชันใหม่)double widthInMm = UnitUtils.ConvertFromInternalUnits(widthInFeet, DisplayUnitType.DUT_MILLIMETERS); - แบบใหม่ (Revit 2022 - 2026+): มีการยกเลิก
DisplayUnitTypeไปอย่างถาวร และเปลี่ยนไปใช้คลาสระบุตัวตนสากลของ Autodesk ที่เรียกว่าForgeTypeIdเพื่อรองรับการระบุหน่วยของระบบคลาวด์ร่วมด้วย:// วิธีสากลแบบใหม่ (แนะนำสำหรับยุคปัจจุบัน)double widthInMm = UnitUtils.ConvertFromInternalUnits(widthInFeet, UnitTypeId.Millimeters);
💡 โค้ดตัวอย่างการเขียนรองรับหน่วยวัดแบบผสมผสาน (Cross-version Unit Converter)
Section titled “💡 โค้ดตัวอย่างการเขียนรองรับหน่วยวัดแบบผสมผสาน (Cross-version Unit Converter)”หากคุณจำเป็นต้องเขียนสคริปต์แปลงหน่วยฟุตให้เป็นมิลลิเมตร โดยให้รันผ่านได้ทั้งบน Revit 2021 (แบบเก่า) และ Revit 2026 (แบบใหม่) ในไฟล์ซอร์สโค้ดกลางชุดเดียวกัน ให้ใช้สคริปต์ผสมผสานนี้ครับ:
using Autodesk.Revit.DB;
namespace RevitToolkit;
public static class UnitConverter{ public static double ConvertFeetToMm(double feetValue) {#if REVIT2027 || REVIT2026 || REVIT2025 // สำหรับ Revit เวอร์ชันใหม่ (2025-2027+) ที่เปลี่ยนไปใช้ ForgeTypeId return UnitUtils.ConvertFromInternalUnits(feetValue, UnitTypeId.Millimeters);#else // สำหรับ Revit เวอร์ชันเก่าที่ยังคงค้างอยู่กับระบบเดิม return UnitUtils.ConvertFromInternalUnits(feetValue, DisplayUnitType.DUT_MILLIMETERS);#endif }}การทำความเข้าใจกับจุดแตกต่างทางเทคนิคของเวอร์ชัน .NET และการเตรียมรับมือกับการตัดถอนคำสั่งเก่า (Deprecated APIs) เหล่านี้ จะช่วยแต่งตั้งให้คุณมีทักษะระดับสถาปนิกซอฟต์แวร์ที่สามารถสร้างปลั๊กอินแชร์งานดูแลรักษาในองค์กรได้อย่างยั่งยืนและแข็งแกร่งที่สุดครับ!