タイトル: エラーメッセージの設定方法
SEOタイトル: Revit API エラーメッセージ表示完全ガイド (TaskDialog/Exceptions)
| この記事の要点 |
|
Revit API でメッセージを出す主な方法
| 方法 | 用途 | 推奨度 |
|---|---|---|
| TaskDialog.Show | シンプルな OK/Cancel 通知 | ★★★ 最推奨 |
| TaskDialog インスタンス | 詳細テキスト、複数ボタン、リンク付き | ★★★ |
| FailureMessage / FailureDefinition | ジオメトリ検証など Revit ネイティブ警告に統合 | ★★★ ジオメトリ系 |
| System.Windows.Forms.MessageBox | WinForms 互換 | ★ 非推奨 (UI 統合悪) |
| WPF Window / Dialog | カスタム UI 必要時 | ★★ 中 |
| Debug.WriteLine / ログファイル | 開発者向けデバッグ情報 | ★★★ 並行使用 |
TaskDialog.Show (最も簡単)
using Autodesk.Revit.UI;
// 最小: タイトルとメッセージ
TaskDialog.Show("情報", "処理が完了しました。");
// 戻り値で OK/Cancel 判定
var res = TaskDialog.Show(
"確認",
"選択した要素を削除しますか?",
TaskDialogCommonButtons.Yes | TaskDialogCommonButtons.No,
TaskDialogResult.No);
if (res == TaskDialogResult.Yes) {
// 削除処理
}
TaskDialog インスタンス (詳細情報、リンク、複数ボタン)
using Autodesk.Revit.UI;
var td = new TaskDialog("ジオメトリ検証エラー") {
MainInstruction = "壁が他の要素と干渉しています",
MainContent = "Wall ID: 12345 が、Floor ID: 6789 と干渉します。\n" +
"この状態では IFC エクスポートが失敗する可能性があります。",
ExpandedContent = "詳細:\n" +
" - 干渉体積: 0.45 m^3\n" +
" - 干渉箇所: (12.5, 8.3, 0.0) - (13.2, 8.7, 3.0)",
FooterText = "<a href=\"https://help.example.com/clash\">解決方法</a>",
TitleAutoPrefix = false,
AllowCancellation = true,
CommonButtons = TaskDialogCommonButtons.Close,
DefaultButton = TaskDialogResult.Close,
};
td.AddCommandLink(TaskDialogCommandLinkId.CommandLink1, "Wall を移動", "干渉が解消される位置に移動します");
td.AddCommandLink(TaskDialogCommandLinkId.CommandLink2, "そのまま続行", "警告を無視して処理を続行します");
var result = td.Show();
switch (result) {
case TaskDialogResult.CommandLink1: MoveWall(); break;
case TaskDialogResult.CommandLink2: ContinueAnyway(); break;
}
Exception を捕捉してユーザ通知
Revit API の例外は Autodesk.Revit.Exceptions 名前空間に定義されています:
using Autodesk.Revit.UI;
using ARExc = Autodesk.Revit.Exceptions;
using System.Diagnostics;
public Result Execute(ExternalCommandData cmd, ref string msg, ElementSet elems) {
UIApplication uiapp = cmd.Application;
Document doc = uiapp.ActiveUIDocument.Document;
try {
using (var tx = new Transaction(doc, "Add Wall")) {
tx.Start();
// ... API 呼び出し ...
tx.Commit();
}
TaskDialog.Show("完了", "壁を追加しました。");
return Result.Succeeded;
} catch (ARExc.InvalidOperationException ex) {
// トランザクション外での編集など
msg = "無効な操作: " + ex.Message;
ShowError("操作エラー", ex);
return Result.Failed;
} catch (ARExc.ArgumentException ex) {
// 引数違反
msg = "引数エラー: " + ex.Message;
ShowError("引数エラー", ex);
return Result.Failed;
} catch (ARExc.OperationCanceledException) {
// ユーザがキャンセル → 通知不要
return Result.Cancelled;
} catch (System.Exception ex) {
msg = "予期せぬエラー: " + ex.Message;
ShowError("システムエラー", ex);
Debug.WriteLine(ex.ToString());
return Result.Failed;
}
}
private void ShowError(string title, System.Exception ex) {
var td = new TaskDialog(title) {
MainInstruction = ex.Message,
MainContent = "詳細はログを確認してください。",
ExpandedContent = ex.ToString(),
CommonButtons = TaskDialogCommonButtons.Close,
};
td.Show();
}
FailureMessage / FailureDefinition (Revit ネイティブ警告に統合)
Revit には独自の警告フレームワークがあり、トランザクション中に FailureMessage を発行すると、Revit 標準の警告ダイアログ (Show / Resolve / Cancel) に統合表示されます。複数警告がまとめて出る、Resolve 操作が選べる、エクスポート時に再表示できる等のメリットあり。
using Autodesk.Revit.DB;
// 1. FailureDefinition の登録 (アプリ起動時に 1 回)
public class App : IExternalApplication {
public static FailureDefinitionId WallClashFailureId;
public Result OnStartup(UIControlledApplication app) {
Guid guid = new Guid("12345678-1234-1234-1234-123456789012");
WallClashFailureId = new FailureDefinitionId(guid);
FailureDefinition.CreateFailureDefinition(
WallClashFailureId,
FailureSeverity.Warning,
"壁が他の要素と干渉しています。");
return Result.Succeeded;
}
public Result OnShutdown(UIControlledApplication app) => Result.Succeeded;
}
// 2. トランザクション中に発行
using (var tx = new Transaction(doc, "Check Wall")) {
tx.Start();
// ... 検証ロジック ...
if (clash) {
var fm = new FailureMessage(App.WallClashFailureId);
fm.SetFailingElement(wall.Id);
doc.PostFailure(fm);
}
tx.Commit(); // ★ コミット時に Revit が警告ダイアログ表示
}
System.Windows.Forms.MessageBox (旧式)
WinForms から移植した既存コードでは使われがちですが、Revit 2024+ では DPI スケーリング不整合、UI スレッド競合、モーダル親ウィンドウ未指定等の問題が発生しやすいので、新規コードでは TaskDialog を使うべきです。
using System.Windows.Forms;
// 旧式: 親ウィンドウを指定して使う必要あり
var owner = new WindowWrapper(uiapp.MainWindowHandle); // System.Windows.Forms.IWin32Window
MessageBox.Show(owner, "メッセージ", "タイトル",
MessageBoxButtons.OKCancel, MessageBoxIcon.Warning);
// IWin32Window ラッパー
public class WindowWrapper : System.Windows.Forms.IWin32Window {
private readonly IntPtr _handle;
public WindowWrapper(IntPtr handle) { _handle = handle; }
public IntPtr Handle => _handle;
}
デバッグログの出力
using System.Diagnostics;
using System.IO;
// 1. Debug.WriteLine (デバッガ または DebugView で確認)
Debug.WriteLine("[MyAddin] Wall created: " + wall.Id);
// 2. ファイルログ (自前)
string logPath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
"MyAddin", "log.txt");
Directory.CreateDirectory(Path.GetDirectoryName(logPath));
File.AppendAllText(logPath,
$"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {message}{Environment.NewLine}");
// 3. NLog (NuGet) - 推奨
private static readonly NLog.Logger Log = NLog.LogManager.GetCurrentClassLogger();
Log.Info("Wall created: {WallId}", wall.Id);
Log.Error(ex, "Failed to create wall");
エラー / 警告 / 情報の使い分け
| 種類 | UI | 使うべき場面 |
|---|---|---|
| 情報 (Info) | TaskDialog (アイコン無し or 情報) | 処理完了、件数報告 |
| 警告 (Warning) | TaskDialog Warning / FailureSeverity.Warning | 続行可能だが注意点あり |
| エラー (Error) | TaskDialog Error / FailureSeverity.Error | 続行不可、ユーザ対応必要 |
| 重大 (Critical) | TaskDialog + ログ + 上位コミット中止 | データ破損リスク |
| キャンセル | 通知なしで Result.Cancelled 返却 | ユーザの明示的中止 |
Revit 2024+ の新 UI
Revit 2024 以降、TaskDialog 自体は変わりませんが、ダーク モード対応、DPI 改善、リボン UI のリフレッシュが行われました。自前 WPF ウィンドウを使う場合はThemeManager でダークテーマ追従が推奨されます。
よくある落とし穴
| 症状 | 原因 | 対処 |
|---|---|---|
| TaskDialog が Revit の裏に出る | 親ウィンドウ未指定 | TaskDialog の場合は基本不要。WPF の場合は WindowInteropHelper で親 HWND 指定 |
| 例外が握り潰される | catch せず IExternalCommand から Result.Succeeded 返却 | 必ず try/catch + Result.Failed |
| トランザクション中に MessageBox | UI スレッドブロック | FailureMessage を使う |
| 多発するエラーで OK 連打地獄 | ループ内で TaskDialog | 件数集約してから 1 度だけ表示 |
FAQ
Q: 非同期処理から TaskDialog を呼びたい
A: Revit API はUI スレッドからしか操作できません。UIApplication.Idling イベントや ExternalEvent 経由でメインスレッドに戻して呼んでください。
Q: TaskDialog にチェックボックス「次回から表示しない」を入れたい
A: VerificationText プロパティをセット、表示後 WasVerificationChecked で取得。値は自前で永続化 (User Settings 等)。
Q: ログを Revit のジャーナルファイルに出したい
A: ジャーナルは Revit 専用なので直接書込み非推奨。自前ログを別途出力するのが標準です。
Q: 多言語化したい
A: メッセージリソース (.resx) を用意し、Application.Language から現在の言語を取得して切替えるのが定番です。