应用程序名称:ModelessForm_IdlingEvent

Revit 平台:所有版本

Revit 版本:2013.0

首次发布于:2013.0

编程语言:C#

技能级别:中级

类别:基础

类型:ExternalCommand ExternalApplication

主题:显示无模式窗体(Idling 事件)

摘要:

该示例演示如何利用 Idling 事件从外部无模式对话框与 Revit API 进行通信。

类:

Autodesk.Revit.DB;

Autodesk.Revit.UI;

Autodesk.Revit.UI.Events;

项目文件:

Command.cs

包含从接口 IExternalCommand 继承并实现 Execute 方法的 Command 类。

 

Application.cs

包含从接口 IExternalApplication 继承并实现其方法的 Command 类。

 

Request.cs

包含当前请求的变量绑定的类。

 

RequestHandler.cs

带有执行对话框用户发出的请求的方法的类。

 

ModelessForm.cs

我们无模式对话框的类。

描述:

该示例演示如何利用 Idling 事件从外部无模式对话框与 Revit API 进行通信。

说明:

1. 启动 Revit 并创建一个新文档。

2. 创建几堵墙,并在其上添加一些门——保留在平面图视图中。

3. 启动 AddIn 命令——“显示无模式窗体(Idling 事件)”。

4. 当对话框出现时,选择一些门。

5. 使用无模式对话框中的命令按钮操纵门。

源代码

完整的源代码请加入QQ群649037449,在群文件中下载RevitSDK.exe,解压后在文件夹中搜索本文中应用程序名称即可获得完整源码

Application.cs

//
// (C) Copyright 2003-2019 by Autodesk, Inc. All rights reserved.
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.

//
// AUTODESK PROVIDES THIS PROGRAM 'AS IS' AND WITH ALL ITS FAULTS.
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC.
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
//
// Use, duplication, or disclosure by the U.S. Government is subject to
// restrictions set forth in FAR 52.227-19 (Commercial Computer
// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii)
// (Rights in Technical Data and Computer Software), as applicable. 

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.IO;

using Autodesk;
using Autodesk.Revit;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.UI.Events;

namespace Revit.SDK.Samples.ModelessForm_IdlingEvent.CS
{
    /// <summary>
    /// Implements the Revit add-in interface IExternalApplication
    /// </summary>
    public class Application : IExternalApplication
    {
        // class instance
        internal static Application thisApp = null;
        // ModelessForm instance
        private ModelessForm m_MyForm;
        
        #region IExternalApplication Members
        /// <summary>
        /// Implements the OnShutdown event
        /// </summary>
        /// <param name="application"></param>
        /// <returns></returns>
        public Result OnShutdown(UIControlledApplication application)
        {
            if (m_MyForm != null && !m_MyForm.IsDisposed)
            {
                m_MyForm.Dispose();
                m_MyForm = null;

                // if we've had a dialog, we had subscribed
                application.Idling -= IdlingHandler;
            }

            return Result.Succeeded;
        }

        /// <summary>
        /// Implements the OnStartup event
        /// </summary>
        /// <param name="application"></param>
        /// <returns></returns>
        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;
        }

        /// <summary>
        ///   This method creates and shows a modeless dialog, unless it already exists.
        /// </summary>
        /// <remarks>
        ///   The external command invokes this on the end-user's request
        /// </remarks>
        /// 
        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;
            }
        }

        /// <summary>
        ///   A handler for the Idling event.
        /// </summary>
        /// <remarks>
        ///   We keep the handler very simple. First we check
        ///   if we still have the dialog. If not, we unsubscribe from Idling,
        ///   for we no longer need it and it makes Revit speedier.
        ///   If we do have the dialog around, we check if it has a request ready
        ///   and process it accordingly.
        /// </remarks>
        /// 
        public void IdlingHandler(object sender, IdlingEventArgs args)
        {
            UIApplication uiapp = sender as UIApplication;

            if (m_MyForm.IsDisposed)
            {
                uiapp.Idling -= IdlingHandler;
                return;
            }
            else   // dialog still exists
            {
                // fetch the request from the dialog

                RequestId request = m_MyForm.Request.Take();

                if (request != RequestId.None)
                {
                    try
                    {
                        // we take the request, if any was made,
                        // and pass it on to the request executor

                        RequestHandler.Execute(uiapp, request);
                    }
                    finally
                    {
                        // The dialog may be in its waiting state;
                        // make sure we wake it up even if we get an exception.

                        m_MyForm.WakeUp();
                    }
                }
            }

            return;
        }

        #endregion
    }
}

Request.cs

//
// (C) Copyright 2003-2019 by Autodesk, Inc.
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted,
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.
//
// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC.
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
//
// Use, duplication, or disclosure by the U.S. Government is subject to
// restrictions set forth in FAR 52.227-19 (Commercial Computer
// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii)
// (Rights in Technical Data and Computer Software), as applicable.
//
using System;
using System.Threading;

namespace Revit.SDK.Samples.ModelessForm_IdlingEvent.CS
{
    /// <summary>
    ///   A list of requests the dialog has available
    /// </summary>
    /// 
    public enum RequestId : int
    {
        /// <summary>
        /// None
        /// </summary>
        None = 0,
        /// <summary>
        /// "Delete" request
        /// </summary>
        Delete = 1,
        /// <summary>
        /// "FlipLeftRight" request
        /// </summary>
        FlipLeftRight = 2,
        /// <summary>
        /// "FlipInOut" request
        /// </summary>
        FlipInOut = 3,
        /// <summary>
        /// "MakeRight" request
        /// </summary>
        MakeRight = 4,
        /// <summary>
        /// "MakeLeft" request
        /// </summary>
        MakeLeft = 5,
        /// <summary>
        /// "TurnOut" request
        /// </summary>
        TurnOut = 6,
        /// <summary>
        /// "TurnIn" request
        /// </summary>
        TurnIn = 7,
        /// <summary>
        /// "Rotate" request
        /// </summary>
        Rotate = 8
    }


    /// <summary>
    ///   A class around a variable holding the current request.
    /// </summary>
    /// <remarks>
    ///   Access to it is made thread-safe, even though we don't necessarily
    ///   need it if we always disable the dialog between individual requests.
    /// </remarks>
    /// 
    public class Request
    {
        // Storing the value as a plain Int makes using the interlocking mechanism simpler
        private int m_request = (int)RequestId.None;

        /// <summary>
        ///   Take - The Idling handler calls this to obtain the latest request. 
        /// </summary>
        /// <remarks>
        ///   This is not a getter! It takes the request and replaces it
        ///   with 'None' to indicate that the request has been "passed on".
        /// </remarks>
        /// 
        public RequestId Take()
        {
            return (RequestId)Interlocked.Exchange(ref m_request, (int)RequestId.None);
        }

        /// <summary>
        ///   Make - The Dialog calls this when the user presses a command button there. 
        /// </summary>
        /// <remarks>
        ///   It replaces any older request previously made.
        /// </remarks>
        /// 
        public void Make(RequestId request)
        {
            Interlocked.Exchange(ref m_request, (int)request);
        }
    }
}

RequestHandler.cs

//
// (C) Copyright 2003-2019 by Autodesk, Inc.
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted,
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.
//
// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC.
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
//
// Use, duplication, or disclosure by the U.S. Government is subject to
// restrictions set forth in FAR 52.227-19 (Commercial Computer
// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii)
// (Rights in Technical Data and Computer Software), as applicable.
//
using System;
using System.Collections.Generic;

using Autodesk.Revit.DB;
using Autodesk.Revit.UI;

namespace Revit.SDK.Samples.ModelessForm_IdlingEvent.CS
{
    /// <summary>
    ///   A class with methods to execute requests made by the dialog user.
    /// </summary>
    /// 
    public static class RequestHandler
    {
        // A trivial delegate, but handy
        private delegate void DoorOperation(FamilyInstance e);


        /// <summary>
        ///   The top function that distributes requests to individual methods. 
        /// </summary>
        /// 
        public static void Execute(UIApplication uiapp, RequestId reqest)
        {
            switch (reqest)
            {
                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;
                    }
            }

            return;
        }


        /// <summary>
        ///   The main door-modification subroutine - called from every request 
        /// </summary>
        /// <remarks>
        ///   It searches the current selection for all doors
        ///   and if it finds any it applies the requested operation to them
        /// </remarks>
        /// <param name="uiapp">The Revit application object</param>
        /// <param name="text">Caption of the transaction for the operation.</param>
        /// <param name="operation">A delegate to perform the operation on an instance of a door.</param>
        /// 
        private static void ModifySelectedDoors(UIApplication uiapp, String text, DoorOperation operation)
        {
            UIDocument uidoc = uiapp.ActiveUIDocument;

            // check if there is anything selected in the active document

            if ((uidoc != null) && (uidoc.Selection != null))
            {
                ICollection<ElementId> selElements = uidoc.Selection.GetElementIds();
                if (selElements.Count > 0)
                {
                    // Filter out all doors from the current selection

                    FilteredElementCollector collector = new FilteredElementCollector(uidoc.Document, selElements);
                    ICollection<Element> doorset = collector.OfCategory(BuiltInCategory.OST_Doors).ToElements();

                    if (doorset != null)
                    {
                        // Since we'll modify the document, we need a transaction
                        // It's best if a transaction is scoped by a 'using' block
                        using (Transaction trans = new Transaction(uidoc.Document))
                        {
                            // The name of the transaction was given as an argument

                            if (trans.Start(text) == TransactionStatus.Started)
                            {
                                // apply the requested operation to every door

                                foreach (FamilyInstance door in doorset)
                                {
                                    operation(door);
                                }

                                trans.Commit();
                            }
                        }
                    }
                }
            }
        }


        //////////////////////////////////////////////////////////////////////////
        //
        // Helpers - simple delegates operating upon an instance of a door

        private static void FlipHandAndFace(FamilyInstance e)
        {
            e.flipFacing(); e.flipHand();
        }

        // Note: The door orientation [left/right] is according the common
        // conventions used by the building industry in the Czech Republic.
        // If the convention is different in your county (like in the U.S),
        // swap the code of the MakeRight and MakeLeft methods.

        private static void MakeLeft(FamilyInstance e)
        {
            if (e.FacingFlipped ^ e.HandFlipped) e.flipHand();
        }

        private static void MakeRight(FamilyInstance e)
        {
            if (!(e.FacingFlipped ^ e.HandFlipped)) e.flipHand();
        }

        // Note: The In|Out orientation depends on the position of the
        // wall the door is in; therefore it does not necessary indicates
        // the door is facing Inside, or Outside, respectively.
        // The presented implementation is good enough to demonstrate
        // how to flip a door, but the actual algorithm will likely
        // have to be changes in a read-world application.

        private static void TurnIn(FamilyInstance e)
        {
            if (!e.FacingFlipped) e.flipFacing();
        }

        private static void TurnOut(FamilyInstance e)
        {
            if (e.FacingFlipped) e.flipFacing();
        }

    }  // class

}  // namespace

ModelessForm.cs

//
// (C) Copyright 2003-2019 by Autodesk, Inc.
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted,
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.
//
// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC.
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
//
// Use, duplication, or disclosure by the U.S. Government is subject to
// restrictions set forth in FAR 52.227-19 (Commercial Computer
// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii)
// (Rights in Technical Data and Computer Software), as applicable.
//
namespace Revit.SDK.Samples.ModelessForm_IdlingEvent.CS
{
    partial class ModelessForm
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.btnExit = new System.Windows.Forms.Button();
            this.btnDeleted = new System.Windows.Forms.Button();
            this.btnFlipUpDown = new System.Windows.Forms.Button();
            this.btnFlipLeftRight = new System.Windows.Forms.Button();
            this.btnFlipLeft = new System.Windows.Forms.Button();
            this.btnFlipRight = new System.Windows.Forms.Button();
            this.btnFlipUp = new System.Windows.Forms.Button();
            this.btnFlipDown = new System.Windows.Forms.Button();
            this.btnRotate = new System.Windows.Forms.Button();
            this.SuspendLayout();
            // 
            // btnExit
            // 
            this.btnExit.Location = new System.Drawing.Point(66, 146);
            this.btnExit.Name = "btnExit";
            this.btnExit.Size = new System.Drawing.Size(89, 23);
            this.btnExit.TabIndex = 0;
            this.btnExit.Text = "Exit";
            this.btnExit.UseVisualStyleBackColor = true;
            this.btnExit.Click += new System.EventHandler(this.btnExit_Click);
            // 
            // btnDeleted
            // 
            this.btnDeleted.Location = new System.Drawing.Point(115, 102);
            this.btnDeleted.Name = "btnDeleted";
            this.btnDeleted.Size = new System.Drawing.Size(89, 24);
            this.btnDeleted.TabIndex = 8;
            this.btnDeleted.Text = "Delete";
            this.btnDeleted.UseVisualStyleBackColor = true;
            this.btnDeleted.Click += new System.EventHandler(this.btnDelete_Click);
            // 
            // btnFlipUpDown
            // 
            this.btnFlipUpDown.Location = new System.Drawing.Point(115, 12);
            this.btnFlipUpDown.Name = "btnFlipUpDown";
            this.btnFlipUpDown.Size = new System.Drawing.Size(89, 24);
            this.btnFlipUpDown.TabIndex = 2;
            this.btnFlipUpDown.Text = "In / Out";
            this.btnFlipUpDown.UseVisualStyleBackColor = true;
            this.btnFlipUpDown.Click += new System.EventHandler(this.btnFlipInOut_Click);
            // 
            // btnFlipLeftRight
            // 
            this.btnFlipLeftRight.Location = new System.Drawing.Point(12, 12);
            this.btnFlipLeftRight.Name = "btnFlipLeftRight";
            this.btnFlipLeftRight.Size = new System.Drawing.Size(89, 24);
            this.btnFlipLeftRight.TabIndex = 1;
            this.btnFlipLeftRight.Text = "Left / Right";
            this.btnFlipLeftRight.UseVisualStyleBackColor = true;
            this.btnFlipLeftRight.Click += new System.EventHandler(this.btnFlipLeftRight_Click);
            // 
            // btnFlipLeft
            // 
            this.btnFlipLeft.Location = new System.Drawing.Point(12, 42);
            this.btnFlipLeft.Name = "btnFlipLeft";
            this.btnFlipLeft.Size = new System.Drawing.Size(89, 24);
            this.btnFlipLeft.TabIndex = 3;
            this.btnFlipLeft.Text = "Left";
            this.btnFlipLeft.UseVisualStyleBackColor = true;
            this.btnFlipLeft.Click += new System.EventHandler(this.btnFlipLeft_Click);
            // 
            // btnFlipRight
            // 
            this.btnFlipRight.Location = new System.Drawing.Point(12, 72);
            this.btnFlipRight.Name = "btnFlipRight";
            this.btnFlipRight.Size = new System.Drawing.Size(89, 24);
            this.btnFlipRight.TabIndex = 5;
            this.btnFlipRight.Text = "Right";
            this.btnFlipRight.UseVisualStyleBackColor = true;
            this.btnFlipRight.Click += new System.EventHandler(this.btnFlipRight_Click);
            // 
            // btnFlipUp
            // 
            this.btnFlipUp.Location = new System.Drawing.Point(115, 42);
            this.btnFlipUp.Name = "btnFlipUp";
            this.btnFlipUp.Size = new System.Drawing.Size(89, 24);
            this.btnFlipUp.TabIndex = 4;
            this.btnFlipUp.Text = "Out";
            this.btnFlipUp.UseVisualStyleBackColor = true;
            this.btnFlipUp.Click += new System.EventHandler(this.btnFlipOut_Click);
            // 
            // btnFlipDown
            // 
            this.btnFlipDown.Location = new System.Drawing.Point(115, 72);
            this.btnFlipDown.Name = "btnFlipDown";
            this.btnFlipDown.Size = new System.Drawing.Size(89, 24);
            this.btnFlipDown.TabIndex = 6;
            this.btnFlipDown.Text = "In";
            this.btnFlipDown.UseVisualStyleBackColor = true;
            this.btnFlipDown.Click += new System.EventHandler(this.btnFlipIn_Click);
            // 
            // btnRotate
            // 
            this.btnRotate.Location = new System.Drawing.Point(12, 102);
            this.btnRotate.Name = "btnRotate";
            this.btnRotate.Size = new System.Drawing.Size(89, 24);
            this.btnRotate.TabIndex = 7;
            this.btnRotate.Text = "Rotate";
            this.btnRotate.UseVisualStyleBackColor = true;
            this.btnRotate.Click += new System.EventHandler(this.btnRotate_Click);
            // 
            // ModelessForm
            // 
            this.AcceptButton = this.btnExit;
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(216, 184);
            this.Controls.Add(this.btnRotate);
            this.Controls.Add(this.btnFlipRight);
            this.Controls.Add(this.btnFlipLeft);
            this.Controls.Add(this.btnFlipLeftRight);
            this.Controls.Add(this.btnFlipDown);
            this.Controls.Add(this.btnFlipUp);
            this.Controls.Add(this.btnFlipUpDown);
            this.Controls.Add(this.btnDeleted);
            this.Controls.Add(this.btnExit);
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
            this.MaximizeBox = false;
            this.MinimizeBox = false;
            this.Name = "ModelessForm";
            this.Opacity = 0.75D;
            this.ShowInTaskbar = false;
            this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
            this.Text = "Door Operator (Idling Event)";
            this.TopMost = true;
            this.ResumeLayout(false);

        }

        #endregion

        private System.Windows.Forms.Button btnExit;
        private System.Windows.Forms.Button btnDeleted;
        private System.Windows.Forms.Button btnFlipUpDown;
        private System.Windows.Forms.Button btnFlipLeftRight;
        private System.Windows.Forms.Button btnFlipLeft;
        private System.Windows.Forms.Button btnFlipRight;
        private System.Windows.Forms.Button btnFlipUp;
        private System.Windows.Forms.Button btnFlipDown;
        private System.Windows.Forms.Button btnRotate;
    }
}