Revit SDK 介绍:ModelessForm_ExternalEvent & ModelessForm_IdlingEvent

前言

ModelessForm_ExternalEvent,这个例子主要介绍的是 Revit External Event,用来生成非模态对话框。可以理解为,在不打断 Revit 正常操作的情况下,响应用户的请求。

内容

在开始之前,先了解一下 External Event,可以参考官网:External Events
使用 External Event 的基本逻辑:

  1. IExternalEventHandler这个接口来实现一个事件处理的 handler 类;
  2. 用静态方法 ExternalEvent.Create() 创建一个 ExternalEvent
  3. 在这个非模块对话框中需要 Revit 去进行操作的时候,调用 ExternalEvent.Raise()
  4. 在 Revit 空闲的时候,它会调用用户实现的方法 IExternalEventHandler.Execute() 。

IExternalEventHandler

用户实现一个自己的 IExternalEventHandler,这个用户的处理函数,Revit 最终会在空闲的时候调用这个类的 Execute 方法。

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.Create() 创建一个 ExternalEvent

public class ExternalEventExampleApp : IExternalApplication
{
    // ExternalEventExample 是 IExternalEventHandler 的一个实现
    public static ExternalEventExampleApp thisApp = null;
    // 非模态对话框的实例
    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;   // 会在用户触发 command 的时候被初始化
        thisApp = this;  // 记录 revit application instance

        return Result.Succeeded;
    }

    //   External command 会调用这个方法
    public void ShowForm(UIApplication uiapp)
    {
        // 如果对话框还没有被创建,就创建一个
        if (m_MyForm == null || m_MyForm.IsDisposed)
        {
            // 事件处理的类
            ExternalEventExample handler = new ExternalEventExample();

            // 用静态方法 `ExternalEvent.Create()` 创建一个 `ExternalEvent` 
            ExternalEvent exEvent = ExternalEvent.Create(handler);

            // 把 handler 和 exEvent 都传给这个非模态对话框,最终非模态对话框通过它们来处理用户的请求
            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;
        }
    }
}

Raise Event

通过 m_ExEvent.Raise(),让 Revit 来处理用户的请求。

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();
    }
}

ModelessForm_ExternalEvent

最终效果如下:
Revit SDK 介绍:ModelessForm_ExternalEvent & ModelessForm_IdlingEvent_第1张图片
对应的消息处理的类 RequestHandler 实现了 IExternalEventHandler

public void Execute(UIApplication uiapp)
{
   try
   {
      switch (Request.Take())
      {
         case RequestId.None:
         {
            return;  // no request at this time -> we can leave immediately
         }
         case RequestId.Delete:
         {
            ModifySelectedDoors(uiapp, "Delete doors", e => e.Document.Delete(e.Id));
            break;
         }
         case RequestId.FlipLeftRight:
         {
            ModifySelectedDoors(uiapp, "Flip door Hand", e => e.flipHand());
            break;
         }
         case RequestId.FlipInOut:
         {
            ModifySelectedDoors(uiapp, "Flip door Facing", e => e.flipFacing());
            break;
         }
         case RequestId.MakeLeft:
         {
            ModifySelectedDoors(uiapp, "Make door Left", MakeLeft);
            break;
         }
         case RequestId.MakeRight:
         {
            ModifySelectedDoors(uiapp, "Make door Right", MakeRight);
            break;
         }
         case RequestId.TurnOut:
         {
            ModifySelectedDoors(uiapp, "Place door Out", TurnOut);
            break;
         }
         case RequestId.TurnIn:
         {
            ModifySelectedDoors(uiapp, "Place door In", TurnIn);
            break;
         }
         case RequestId.Rotate:
         {
            ModifySelectedDoors(uiapp, "Rotate door", FlipHandAndFace);
            break;
         }
         default:
         {
            // some kind of a warning here should
            // notify us about an unexpected request 
            break;
         }
      }
   }
   finally
   {
      Application.thisApp.WakeFormUp();
   }

   return;
}

每一个动作最终都用调用 ModifySelectedDoors,这里用了策略设计模式,把各种类型的改变都包装成一个函数。ModifySelectedDoors 本身的逻辑很简单,就是把门过滤出来,然后对每个门调用改变的函数。

private void ModifySelectedDoors(UIApplication uiapp, String text, DoorOperation operation)
{
   UIDocument uidoc = uiapp.ActiveUIDocument;
   // 判断是否有活动的文档和选择集
   if ((uidoc != null) && (uidoc.Selection != null))
   {
      ICollection<ElementId> selElements = uidoc.Selection.GetElementIds();
      if (selElements.Count > 0)
      {
         // 从当前的选择集中过滤出所有的门
         FilteredElementCollector collector = new FilteredElementCollector(uidoc.Document, selElements);
         ICollection<Element> doorset = collector.OfCategory(BuiltInCategory.OST_Doors).ToElements();

         if (doorset != null)
         {
            using (Transaction trans = new Transaction(uidoc.Document))
            {
               // The name of the transaction was given as an argument
               if (trans.Start(text) == TransactionStatus.Started)
               {
                  // 对每一个门进行修改
                  foreach (FamilyInstance door in doorset)
                  {
                     operation(door);
                  }
                  trans.Commit();
               }
            }
         }
      }
   }
}

ModelessForm_IdlingEvent

效果和 ModelessForm_ExternalEvent 一样,差别是处理函数不同。ModelessForm_IdlingEvent 是在 Revit 空闲的时候被调用。
具体逻辑:

  1. 注册 idling 事件
  2. 在idling 处理函数里进行处理

注册 idling 事件

通过 uiapp 来注册空闲事件:

public void ShowForm(UIApplication uiapp)
{
   // If we do not have a dialog yet, create and show it
   if (m_MyForm == null || m_MyForm.IsDisposed)
   {
      m_MyForm = new ModelessForm();
      m_MyForm.Show();

      // if we have a dialog, we need Idling too
      uiapp.Idling += IdlingHandler;
   }
}

idling 事件处理函数

public void IdlingHandler(object sender, IdlingEventArgs args)
{
   UIApplication uiapp = sender as UIApplication;
   if (m_MyForm.IsDisposed)
   {
      uiapp.Idling -= IdlingHandler;
      return;
   }
   else   // 对话框还打开着
   {
      // 从对话框查询用户的请求及内容
      RequestId request = m_MyForm.Request.Take();
      if (request != RequestId.None)
      {
         try
         {
            // 调用具体的处理函数,和ModelessForm_ExternalEvent的处理一致
            RequestHandler.Execute(uiapp, request);
         }
         finally
         {
            // 激活无模态对话框
            m_MyForm.WakeUp();
         }
      }
   }
   return;
}

你可能感兴趣的:(Revit,SDK,介绍,c#)