Skip to content

เขียน Command แรก

โครงสร้างพื้นฐาน

Section titled “โครงสร้างพื้นฐาน”

เริ่มต้นให้คุณสร้างไฟล์ชื่อ Command.cs ในโปรเจ็กต์ และใส่โค้ดตั้งต้นนี้ลงไปครับ:

Command.cs
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
namespace RevitToolkit;
// 1. TransactionMode.Manual: เราจะจัดการการบันทึกสถานะ (แก้ไขโมเดล) ด้วยตัวเอง
[Transaction(TransactionMode.Manual)]
public class Command : IExternalCommand // 2. คลาสถูกสืบทอดจาก IExternalCommand เสมอ
{
// 3. ฟังก์ชันการทำงานหลัก (Entry Point)
public Result Execute(
ExternalCommandData commandData, // เก็บข้อมูลเกี่ยวกับ Application ปัจจุบัน (เอกสารที่เปิดอยู่)
ref string message, // ตัวแปรเก็บค่า error หากประมวลผลล้มเหลว
ElementSet elements) // สำหรับทำไฮไลท์ element เวลาเกิด error
{
// 4. แสดงผลทดสอบที่หน้าจอ
TaskDialog.Show("RevitToolkit", "Hello from Revit 2026");
// 5. ส่งกลับบอก Revit ว่างานสำเร็จ
return Result.Succeeded;
}
}

🔍 ชำแหละโครงสร้างคลาสและเจาะลึก Revit API ที่ใช้

Section titled “🔍 ชำแหละโครงสร้างคลาสและเจาะลึก Revit API ที่ใช้”

ในโค้ด C# สำหรับคำสั่งแรกนี้ มีองค์ประกอบสำคัญของ Revit API ที่ผู้อ่านควรรู้จักเป็นอย่างดี ดังนี้ครับ:

  • มันคืออะไร: เป็นอินเทอร์เฟซหลักของ Autodesk Revit สำหรับกำหนดประเภทวัตถุที่จะทำหน้าที่รับสั่งรันคำสั่งเมื่อผู้ใช้กดปุ่ม
  • หน้าที่ในโค้ด: คลาสใดก็ตามที่ผู้ใช้งานต้องการให้เป็น “ปุ่มกดเครื่องมือย่อย” จะต้องทำการสืบทอด (: IExternalCommand) เสมอ เพื่อเป็นช่องทางให้ Revit ทราบจุดเริ่มต้นรันงาน
  • ทำไมต้องใช้: หากเราสร้างคลาสปกติขึ้นมาเดี่ยวๆ โดยไม่ต่ออินเทอร์เฟซนี้ Revit จะมองข้ามและไม่สามารถโหลดชุดคำสั่งของเราไปประมวลผลได้เลยครับ
  • มันคืออะไร: ฟังก์ชันทางเข้าหลัก (Entry Point) ที่ประกาศไว้ในอินเทอร์เฟซ IExternalCommand
  • หน้าที่ในโค้ด: จะถูกเรียกใช้งานโดยอัตโนมัติจาก Thread หลักของระบบ Revit ทันทีที่มีการกดปุ่มสั่งงานบนหน้าจอ โดยมีพารามิเตอร์ส่งต่อดังนี้:
    • ExternalCommandData commandData: เปรียบเสมือน “กล่องเก็บของเล่นสารพัดประโยชน์” ที่ให้เราดึงข้อมูลแอปพลิเคชัน ตัวแทนไฟล์งานที่เปิดอยู่ (Document) หรือชุดสกรีนพิกัดการเลือกวัตถุของผู้ใช้ (Selection)
    • ref string message: ตัวแปรส่งผ่านข้อความ หากปลั๊กอินของเราทำงานไม่สำเร็จ (คืนค่าเป็น Result.Failed) ข้อความใดๆ ที่เราฝากเขียนไว้ในตัวแปรนี้จะไปปรากฏเป็นกล่องแจ้งเตือนความผิดพลาดบนหน้าจอ Revit ทันที
    • ElementSet elements: ตัวแทนเซตของวัตถุ กรณีปลั๊กอินทำงานล้มเหลว เราสามารถยัดโมเดลที่มีปัญหาใส่ในชุดนี้เพื่อให้ Revit ช่วยเปลี่ยนสีวัตถุเหล่านั้นให้เป็นสีแดงเพื่อช่วยเตือนผู้ใช้ได้
  • มันคืออะไร: ค่าแจกแจงผลการทำงานส่งกลับหลังประมวลผลคำสั่งสำเร็จ
  • หน้าที่ในโค้ด: คืนค่าเพื่อบอกสถานะกับระบบประวัติคำสั่งของ Revit:
    • Result.Succeeded: การทำงานไร้ปัญหา ระบบจะอัปเดตโมเดลเข้าประวัติ
    • Result.Failed: งานทำงานล้มเหลวหรือเกิดข้อผิดพลาด ปลั๊กอินจะหยุดตัวพร้อมยกเลิกการปรับปรุง
    • Result.Cancelled: ผู้ใช้กดปุ่มยกเลิกคำสั่งกลางคัน
  • ทำไมต้องใช้: เพื่อช่วยให้โปรแกรมบริหารจัดการชุดประวัติการกด Undo/Redo ในไฟล์ได้อย่างเรียบร้อยและไม่ค้างคาในอนาคต

4. [Transaction(TransactionMode.Manual)] (Attribute)

Section titled “4. [Transaction(TransactionMode.Manual)] (Attribute)”
  • มันคืออะไร: แอตทริบิวต์กำหนดโหมดรักษาความปลอดภัยของการเขียนฐานข้อมูล Revit
  • หน้าที่ในโค้ด: บอกให้ Revit ทราบว่าคลาส C# ชุดนี้จะขอยืนยัน “เปิด-ปิด และบันทึกประวัติ Transaction ด้วยน้ำมือตัวเองเท่านั้น (Manual)”
  • ทำไมต้องใช้: ปัจจุบัน Autodesk กำหนดให้ใช้วิธีนี้เพื่อให้เขียนโค้ดคลุมความปลอดภัยครอบการแก้ไขไฟล์ ป้องกันข้อมูลของโปรเจ็กต์เสียหาย
  • มันคืออะไร: กล่องหน้าต่างแจ้งเตือนเฉพาะทางของโปรแกรม Revit
  • หน้าที่ในโค้ด: สั่งเปิด Popup ข้อความสีฟ้าเพื่อเช็กสถานะการโหลดได้อย่างรวดเร็ว โดยคำสั่ง TaskDialog.Show("หัวข้อ", "รายละเอียดข้อความ") จะช่วยอำนวยความสะดวกในการแสดงผลงานช่วงต้นโดยไม่ต้องวาดหน้าจอ UI ซับซ้อนด้วยตนเอง