外部事件

Revit API提供了一个外部事件框架,以适应非模态对话框的使用。它是为异步处理量身定制的,其操作类似于具有默认频率的Idling事件。

要使用外部事件框架实现无模式对话框,请执行以下步骤:

  1. 通过从IExternalEventException接口派生来实现外部事件处理程序
  2. 使用静态ExternalEvent.Create()方法创建ExternalEvent
  3. 当需要执行Revit操作的无模式对话框中发生事件时,调用ExternalEvent.Raise()
  4. 当存在可用的空闲时间周期时,Revit将调用IExternalEvents.Execute()方法的实现。

IExternalEventHandler

这是要为外部事件实现的接口。实现此接口的类的实例注册到Revit中,每次引发相应的外部事件时,都会调用此接口的Execute方法。

IExternalEventHandler 只有两个方法要实现,Execute()方法和GetName(),后者应该返回事件的名称。下面是一个基本的实现,它将在引发事件时显示TaskDialog。

**代码区域:实现IExternalEventHandler **

1
2
3
4
5
6
7
8
9
10
11
12
public class ExternalEventExample : IExternalEventHandler
{
public void Execute(UIApplication app)
{
TaskDialog.Show("External Event", "Click Close to close.");
}

public string GetName()
{
return "External Event Example";
}
}

外部事件

ExternalEvent类用于创建ExternalEvent。此类的实例将在事件创建时返回给外部事件的所有者。事件的所有者将使用此实例来通知Revit应调用该事件。Revit将定期检查是否有任何事件已发出信号(引发),并将执行通过调用事件各自处理程序上的Execute方法引发的所有事件。

下面的示例演示IExternalApplication的实现,该IExternalApplication具有从ExternalCommand(显示在代码区域的末尾)调用的ShowForm()方法。ShowForm()方法从上面的例子中创建了一个外部事件处理程序的新实例,创建了一个新的ExternalEvent,然后显示无模式对话框,该对话框稍后将使用传入的ExternalEvent对象来引发事件。

代码区域:创建外部事件

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
public class ExternalEventExampleApp : IExternalApplication
{
// class instance
public static ExternalEventExampleApp thisApp = null;
// ModelessForm instance
private ExternalEventExampleDialog m_MyForm;

public Result OnShutdown(UIControlledApplication application)
{
if (m_MyForm != null && m_MyForm.Visible)
{
m_MyForm.Close();
}

return Result.Succeeded;
}

public Result OnStartup(UIControlledApplication application)
{
m_MyForm = null; // no dialog needed yet; the command will bring it
thisApp = this; // static access to this application instance

return Result.Succeeded;
}

// The external command invokes this on the end-user's request
public void ShowForm(UIApplication uiapp)
{
// If we do not have a dialog yet, create and show it
if (m_MyForm == null || m_MyForm.IsDisposed)
{
// A new handler to handle request posting by the dialog
ExternalEventExample handler = new ExternalEventExample();

// External Event for the dialog to use (to post requests)
ExternalEvent exEvent = ExternalEvent.Create(handler);

// We give the objects to the new dialog;
// The dialog becomes the owner responsible for disposing them, eventually.
m_MyForm = new ExternalEventExampleDialog(exEvent, handler);
m_MyForm.Show();
}
}
}

[Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
public class Command : IExternalCommand
{
public virtual Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
try
{
ExternalEventExampleApp.thisApp.ShowForm(commandData.Application);
return Result.Succeeded;
}
catch (Exception ex)
{
message = ex.Message;
return Result.Failed;
}
}
}

一旦显示非模态对话框,用户就可以与之交互。对话框中的操作可能需要触发Revit中的某些操作。发生这种情况时,将调用ExternalEvent.Raise()方法。下面的示例是一个简单的无模式对话框的代码,该对话框有两个按钮:一个用于引发事件,另一个用于关闭对话框。

代码区域:引发事件

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
public partial class ExternalEventExampleDialog : Form
{
private ExternalEvent m_ExEvent;
private ExternalEventExample m_Handler;

public ExternalEventExampleDialog(ExternalEvent exEvent, ExternalEventExample handler)
{
InitializeComponent();
m_ExEvent = exEvent;
m_Handler = handler;
}

protected override void OnFormClosed(FormClosedEventArgs e)
{
// we own both the event and the handler
// we should dispose it before we are closed
m_ExEvent.Dispose();
m_ExEvent = null;
m_Handler = null;

// do not forget to call the base class
base.OnFormClosed(e);
}

private void closeButton_Click(object sender, EventArgs e)
{
Close();
}

private void showMessageButton_Click(object sender, EventArgs e)
{
m_ExEvent.Raise();
}
}

调用ExternalEvent.Raise()方法时,Revit将等待可用的Idling计时器,然后调用IExternalEventEvent.Execute()方法。在这个简单的例子中,它将显示一个TaskDialog,文本为“Click Close to close.”“,如上面第一个代码区域所示。

有关使用外部事件框架的更复杂示例,请参见SDK中ModelessDialog\ModelessForm_ExternalEvent文件夹下的示例代码。它使用一个带有许多按钮的非模态对话框,IExternalEventEvent实现有一个公共属性来跟踪按下了哪个按钮,因此它可以在Execute()方法中打开该值。

注:翻译自Revit API Developers Guide