应用程序:Ribbon

Revit平台:所有

Revit版本:2011.0

首次发布用于:2010.0

编程语言:C#

技能等级:初级

类别:基础

类型:外部应用

主题:通过功能区API创建自定义功能区

摘要:

此示例演示如何为外接程序创建自定义功能区,以及如何创建不同类型的功能区项目(RibbonPanelPushButtonPulldownButtonStackable ButtonsRadioButtonGroupTextBoxSplitButton)。

相关类:

Autodesk.Revit.ApplicationServices.ControlledApplication

Autodesk.Revit.UI.RibbonPanel

Autodesk.Revit.UI.PushButton

Autodesk.Revit.UI.PulldownButton

Autodesk.Revit.UI.PushButtonData

Autodesk.Revit.UI.PulldownButtonData

Autodesk.Revit.UI.IExternalCommand

Autodesk.Revit.UI.IExternalApplication

项目文件:

RibbonSample.cs

文件包含了类 RibbonSample,该类继承自接口 IExternalApplication,并实现了方法 OnStartUp。该类将添加一些自定义的 Ribbon 按钮,每个按钮都附带有一些简单的功能。这些功能将在 AddInCommands 类中实现。

AddInCommands.cs

文件包含了若干个类,如 CreateWallCreateStructuralWallDeleteWallsXMoveWallsYMoveWalls。这些类分别对应于在“Add-InRibbon 面板上创建的按钮。

描述:

该示例应该提供以下功能:

- 将不同类型的 Ribbon 按钮添加到 Revit 中:(就像下面的截图一样)

  * 面板的第一部分用于创建墙或结构墙。

  * 第二部分用于选择新建墙所在的层、形状,您也可以通过“重置”按钮撤销所做的选择更改。

  * 第三部分用于选择墙类型。

  * 第四部分用于设置新墙的“标记”。

  * 第五部分用于删除或移动墙。

  * 第四和第五部分添加到“Slide-Out”面板中。

 

 

- 第一部分包含一个SplitButton,由两个PushButton组成。

  * Create Wall 用于在 Revit 画布中央创建一堵墙。

  * Create Structural Wall 用于在 Revit 画布中央创建一个结构墙。

- 第二部分包含一个StackedButton,由一个PushButton和两个ComboBox组成。

  * 第一个按钮用于重置用户所做的选择更改。

  * 另外两个ComboBox用于选择层和墙的形状。

- 第三部分包含一个 RadioButtonGroup,供用户选择 WallType

- 第四部分包含一个文本框,用于设置新墙的“标记”。

- 第五部分包含一个StackedButton,由一个PushButton(删除所有墙)和一个PullDownButton(在XY方向移动所有墙)组成)。

 

实施注意事项:

 

- 要将 RibbonPanel 添加到 Revit 中,用户需要实现 IExternalApplication 接口,并在 OnStartup(ControlledApplication) 方法中调用相应的方法来创建 RibbonItems

- 每个面板中的每个按钮都应该有相应的命令来执行。每个按钮对应的命令应该实现 IExternalCommand 接口。

- 使用 ControlledApplication.CreateRibbonPanel(string ribbonName) 将新的面板添加到 Revit 中。

- 使用 RibbonPanel.AddPushButton() 将单个 PushButton 添加到每个面板中。

- 使用 RibbonPanel.AddStackedButtons() 将可堆叠按钮添加到每个面板中。

- 使用 PulldownButton.AddItem() 将子按钮添加到每个下拉按钮中。

- 要设置 Image LargeImage 属性,必须首先创建一个 ImageSource 类,但 ImageSource 是一个抽象类,因此用户必须创建 ImageSource 的子类,例如 BitmapImage

例如: PushButton.Image = new BitmapImage(new Uri(imagePath, UriKind.Absolute))·

说明:

1..addin 文件复制到 Revit 的相应 Addins 文件夹中。您可以通过 RevitAddUtility.dll 找到此文件夹的位置,我们还提供了一个名为ExternalCommand 的示例。

(例如,XP用户的文件夹位置在这里:\Documents and Settings\All Users\Application Data\Autodesk\Revit\Addins\2012

2.Ribbon.dll 和图像文件(bmp)复制到此示例dll的同一目录中。

3.运行 Revit,然后您就可以在 Revit 中看到自定义的 Ribbon 面板。

4.单击每个按钮运行此示例。

  * 单击“结构墙”PushButton多次以在Revit中创建一些墙。

  * 单击 ComboBox RadioButtonGroup 以选择要创建的墙的种类。

  * 单击“删除墙”按钮将删除 Create Wall 命令创建的所有墙。

  * 单击“移动墙”PulldownButton中的两个子按钮以移动墙。

源代码:

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

AddInCommand.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 System.Linq;
using System.Text;
using Autodesk.Revit;
using Autodesk.Revit.DB;
using System.Diagnostics;
using System.IO;
using System.Collections;
using Autodesk.Revit.UI;

namespace Revit.SDK.Samples.Ribbon.CS
{
/// <summary>
/// Implements the Revit add-in interface IExternalCommand, create a wall
/// all the properties for new wall comes from user selection in Ribbon
/// </summary>
[Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
[Autodesk.Revit.Attributes.Regeneration(Autodesk.Revit.Attributes.RegenerationOption.Manual)]
[Autodesk.Revit.Attributes.Journaling(Autodesk.Revit.Attributes.JournalingMode.NoCommandData)]
public class CreateWall : IExternalCommand
{
public static ElementSet CreatedWalls = new ElementSet(); //restore all the walls created by API.

#region IExternalCommand Members Implementation
public Autodesk.Revit.UI.Result Execute(ExternalCommandData revit,
ref string message,
ElementSet elements)
{
Transaction trans = new Transaction(revit.Application.ActiveUIDocument.Document, "CreateWall");
trans.Start();
Autodesk.Revit.UI.UIApplication app = revit.Application;

WallType newWallType = GetNewWallType(app); //get WallType from RadioButtonGroup - WallTypeSelector
Level newWallLevel = GetNewWallLevel(app); //get Level from Combobox - LevelsSelector
List<Curve> newWallShape = GetNewWallShape(app); //get wall Curve from Combobox - WallShapeComboBox
String newWallMark = GetNewWallMark(app); //get mark of new wall from Text box - WallMark

Wall newWall = null;
if ("CreateStructureWall" == this.GetType().Name) //decided by SplitButton
{ newWall = Wall.Create(app.ActiveUIDocument.Document, newWallShape, newWallType.Id, newWallLevel.Id, true); }
else { newWall = Wall.Create(app.ActiveUIDocument.Document, newWallShape, newWallType.Id, newWallLevel.Id, false); }
if (null != newWall)
{
newWall.get_Parameter(BuiltInParameter.ALL_MODEL_MARK).Set(newWallMark); //set new wall's mark
CreatedWalls.Insert(newWall);
}
trans.Commit();
return Autodesk.Revit.UI.Result.Succeeded;
}

#endregion IExternalCommand Members Implementation

#region protected methods
protected WallType GetNewWallType(Autodesk.Revit.UI.UIApplication app)
{
RibbonPanel myPanel = app.GetRibbonPanels()[0];
RadioButtonGroup radioGroupTypeSelector =
GetRibbonItemByName(myPanel, "WallTypeSelector") as RadioButtonGroup;
if (null == radioGroupTypeSelector) { throw new InvalidCastException("Cannot get Wall Type selector!"); }
String wallTypeName = radioGroupTypeSelector.Current.ItemText;
WallType newWallType = null;
FilteredElementCollector collector = new FilteredElementCollector(app.ActiveUIDocument.Document);
ICollection<Element> founds = collector.OfClass(typeof(WallType)).ToElements();
foreach (Element elem in founds)
{
WallType wallType = elem as WallType;
if (wallType.Name.StartsWith(wallTypeName))
{
newWallType = wallType; break;
}
}

return newWallType;
}

protected Level GetNewWallLevel(Autodesk.Revit.UI.UIApplication app)
{
RibbonPanel myPanel = app.GetRibbonPanels()[0];
Autodesk.Revit.UI.ComboBox comboboxLevel =
GetRibbonItemByName(myPanel, "LevelsSelector") as Autodesk.Revit.UI.ComboBox;
if (null == comboboxLevel) { throw new InvalidCastException("Cannot get Level selector!"); }
String wallLevel = comboboxLevel.Current.ItemText;
//find wall type in document
Level newWallLevel = null;
FilteredElementCollector collector = new FilteredElementCollector(app.ActiveUIDocument.Document);
ICollection<Element> founds = collector.OfClass(typeof(Level)).ToElements();
foreach (Element elem in founds)
{
Level level = elem as Level;
if (level.Name.StartsWith(wallLevel))
{
newWallLevel = level; break;
}
}

return newWallLevel;
}

protected List<Curve> GetNewWallShape(Autodesk.Revit.UI.UIApplication app)
{
RibbonPanel myPanel = app.GetRibbonPanels()[0];
Autodesk.Revit.UI.ComboBox comboboxWallShape =
GetRibbonItemByName(myPanel, "WallShapeComboBox") as Autodesk.Revit.UI.ComboBox;
if (null == comboboxWallShape) { throw new InvalidCastException("Cannot get Wall Shape Gallery!"); }
String wallShape = comboboxWallShape.Current.ItemText;
if ("SquareWall" == wallShape) { return GetSquareWallShape(app.Application.Create); }
else if ("CircleWall" == wallShape) { return GetCircleWallShape(app.Application.Create); }
else if ("TriangleWall" == wallShape) { return GetTriangleWallShape(app.Application.Create); }
else { return GetRectangleWallShape(app.Application.Create); }
}

protected String GetNewWallMark(Autodesk.Revit.UI.UIApplication app)
{
RibbonPanel myPanel = app.GetRibbonPanels()[0];
Autodesk.Revit.UI.TextBox textBox =
GetRibbonItemByName(myPanel, "WallMark") as Autodesk.Revit.UI.TextBox;
if (null == textBox) { throw new InvalidCastException("Cannot get Wall Mark TextBox!"); }
String newWallMark;
int newWallIndex = 0;
FilteredElementCollector collector = new FilteredElementCollector(app.ActiveUIDocument.Document);
ICollection<Element> founds = collector.OfClass(typeof(Wall)).ToElements();
foreach (Element elem in founds)
{
Wall wall = elem as Wall;
string wallMark = wall.get_Parameter(BuiltInParameter.ALL_MODEL_MARK).AsString();
if (wallMark.StartsWith(textBox.Value.ToString()) && wallMark.Contains('_'))
{
//get the index for new wall (wall_1, wall_2...)
char[] chars = { '_' };
string[] strings = wallMark.Split(chars);
if (strings.Length >= 2)
{
try
{
int index = Convert.ToInt32(strings[strings.Length - 1]);
if (index > newWallIndex) { newWallIndex = index; }
}
catch (System.Exception)
{
continue;
}
}
}
}
newWallMark = textBox.Value.ToString() + '_' + (newWallIndex + 1);
return newWallMark;
}

protected List<Curve> GetRectangleWallShape(Autodesk.Revit.Creation.Application creApp)
{
//calculate size of Structural and NonStructural walls
int WallsSize = CreateStructureWall.CreatedWalls.Size + CreatedWalls.Size;
List<Curve> curves = new List<Curve>();
//15: distance from each wall, 60: wall length , 60: wall width
Line line1 = Line.CreateBound(new Autodesk.Revit.DB.XYZ(WallsSize * 15, 0, 0), new Autodesk.Revit.DB.XYZ(WallsSize * 15, 60, 0));
Line line2 = Line.CreateBound(new Autodesk.Revit.DB.XYZ(WallsSize * 15, 60, 0), new Autodesk.Revit.DB.XYZ(WallsSize * 15, 60, 40));
Line line3 = Line.CreateBound(new Autodesk.Revit.DB.XYZ(WallsSize * 15, 60, 40), new Autodesk.Revit.DB.XYZ(WallsSize * 15, 0, 40));
Line line4 = Line.CreateBound(new Autodesk.Revit.DB.XYZ(WallsSize * 15, 0, 40), new Autodesk.Revit.DB.XYZ(WallsSize * 15, 0, 0));
curves.Add(line1);
curves.Add(line2);
curves.Add(line3);
curves.Add(line4);
return curves;
}

protected List<Curve> GetSquareWallShape(Autodesk.Revit.Creation.Application creApp)
{
//calculate size of Structural and NonStructural walls
int WallsSize = CreateStructureWall.CreatedWalls.Size + CreatedWalls.Size;
List<Curve> curves = new List<Curve>();
//15: distance from each wall, 40: wall length
Line line1 = Line.CreateBound(new Autodesk.Revit.DB.XYZ(WallsSize * 15, 0, 0), new Autodesk.Revit.DB.XYZ(WallsSize * 15, 40, 0));
Line line2 = Line.CreateBound(new Autodesk.Revit.DB.XYZ(WallsSize * 15, 40, 0), new Autodesk.Revit.DB.XYZ(WallsSize * 15, 40, 40));
Line line3 = Line.CreateBound(new Autodesk.Revit.DB.XYZ(WallsSize * 15, 40, 40), new Autodesk.Revit.DB.XYZ(WallsSize * 15, 0, 40));
Line line4 = Line.CreateBound(new Autodesk.Revit.DB.XYZ(WallsSize * 15, 0, 40), new Autodesk.Revit.DB.XYZ(WallsSize * 15, 0, 0));
curves.Add(line1);
curves.Add(line2);
curves.Add(line3);
curves.Add(line4);
return curves;
}

protected List<Curve> GetCircleWallShape(Autodesk.Revit.Creation.Application creApp)
{
//calculate size of Structural and NonStructural walls
int WallsSize = CreateStructureWall.CreatedWalls.Size + CreatedWalls.Size;
List<Curve> curves = new List<Curve>();
//15: distance from each wall, 40: diameter of circle
Arc arc = Arc.Create(new Autodesk.Revit.DB.XYZ(WallsSize * 15, 20, 0), new Autodesk.Revit.DB.XYZ(WallsSize * 15, 20, 40), new Autodesk.Revit.DB.XYZ(WallsSize * 15, 40, 20));
Arc arc2 = Arc.Create(new Autodesk.Revit.DB.XYZ(WallsSize * 15, 20, 0), new Autodesk.Revit.DB.XYZ(WallsSize * 15, 20, 40), new Autodesk.Revit.DB.XYZ(WallsSize * 15, 0, 20));
curves.Add(arc);
curves.Add(arc2);
return curves;
}

protected List<Curve> GetTriangleWallShape(Autodesk.Revit.Creation.Application creApp)
{
//calculate size of Structural and NonStructural walls
int WallsSize = CreateStructureWall.CreatedWalls.Size + CreatedWalls.Size;
List<Curve> curves = new List<Curve>();
//15: distance from each wall, 40: height of triangle
Line line1 = Line.CreateBound(new Autodesk.Revit.DB.XYZ(WallsSize * 15, 0, 0), new Autodesk.Revit.DB.XYZ(WallsSize * 15, 40, 0));
Line line2 = Line.CreateBound(new Autodesk.Revit.DB.XYZ(WallsSize * 15, 40, 0), new Autodesk.Revit.DB.XYZ(WallsSize * 15, 20, 40));
Line line3 = Line.CreateBound(new Autodesk.Revit.DB.XYZ(WallsSize * 15, 20, 40), new Autodesk.Revit.DB.XYZ(WallsSize * 15, 0, 0));
curves.Add(line1);
curves.Add(line2);
curves.Add(line3);
return curves;
}
#endregion

/// <summary>
/// return the RibbonItem by the input name in a specific panel
/// </summary>
/// <param name="panelRibbon">RibbonPanel which contains the RibbonItem </param>
/// <param name="itemName">name of RibbonItem</param>
/// <return>RibbonItem whose name is same with input string</param>
public RibbonItem GetRibbonItemByName(RibbonPanel panelRibbon, String itemName)
{
foreach (RibbonItem item in panelRibbon.GetItems())
{
if (itemName == item.Name)
{
return item;
}
}

return null;
}
}

/// <summary>
/// Implements the Revit add-in interface IExternalCommand,create a structural wall
/// all the properties for new wall comes from user selection in Ribbon
/// </summary>
[Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
[Autodesk.Revit.Attributes.Regeneration(Autodesk.Revit.Attributes.RegenerationOption.Manual)]
public class CreateStructureWall : CreateWall
{
}

/// <summary>
/// Implements the Revit add-in interface IExternalCommand,
/// delete all the walls which create by Ribbon sample
/// </summary>
[Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
[Autodesk.Revit.Attributes.Regeneration(Autodesk.Revit.Attributes.RegenerationOption.Manual)]
public class DeleteWalls : IExternalCommand
{
#region IExternalCommand Members Implementation
public Autodesk.Revit.UI.Result Execute(ExternalCommandData revit,
ref string message,
ElementSet elements)
{
// delete all the walls which create by RibbonSample
ElementSet wallSet = CreateWall.CreatedWalls;
Transaction trans = new Transaction(revit.Application.ActiveUIDocument.Document, "DeleteWalls");
trans.Start();
foreach (Element e in wallSet)
{
revit.Application.ActiveUIDocument.Document.Delete(e.Id);
}
CreateWall.CreatedWalls.Clear();
trans.Commit();
return Autodesk.Revit.UI.Result.Succeeded;
}
#endregion IExternalCommand Members Implementation
}

/// <summary>
/// Implements the Revit add-in interface IExternalCommand,Move walls, X direction
/// </summary>
[Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
[Autodesk.Revit.Attributes.Regeneration(Autodesk.Revit.Attributes.RegenerationOption.Manual)]
public class XMoveWalls : IExternalCommand
{
#region IExternalCommand Members Implementation

public Autodesk.Revit.UI.Result Execute(ExternalCommandData revit,
ref string message,
ElementSet elements)
{
Transaction trans = new Transaction(revit.Application.ActiveUIDocument.Document, "XMoveWalls");
trans.Start();
IEnumerator iter = CreateWall.CreatedWalls.GetEnumerator();
iter.Reset();
while (iter.MoveNext())
{
Wall wall = iter.Current as Wall;
if (null != wall)
{
wall.Location.Move(new Autodesk.Revit.DB.XYZ(12, 0, 0));
}
}
trans.Commit();
return Autodesk.Revit.UI.Result.Succeeded;
}
#endregion IExternalCommand Members Implementation
}

/// <summary>
/// Implements the Revit add-in interface IExternalCommand,Move walls, Y direction
/// </summary>
[Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
[Autodesk.Revit.Attributes.Regeneration(Autodesk.Revit.Attributes.RegenerationOption.Manual)]
public class YMoveWalls : IExternalCommand
{
#region IExternalCommand Members Implementation

public Autodesk.Revit.UI.Result Execute(ExternalCommandData revit,
ref string message,
ElementSet elements)
{
Transaction trans = new Transaction(revit.Application.ActiveUIDocument.Document, "YMoveWalls");
trans.Start();
IEnumerator iter = CreateWall.CreatedWalls.GetEnumerator();
iter.Reset();
while (iter.MoveNext())
{
Wall wall = iter.Current as Wall;
if (null != wall)
{
wall.Location.Move(new Autodesk.Revit.DB.XYZ(0, 12, 0));
}
}
trans.Commit();
return Autodesk.Revit.UI.Result.Succeeded;
}
#endregion IExternalCommand Members Implementation
}

/// <summary>
/// Implements the Revit add-in interface IExternalCommand,
/// Reset all the Ribbon options to default, such as level, wall type...
/// </summary>
[Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
[Autodesk.Revit.Attributes.Regeneration(Autodesk.Revit.Attributes.RegenerationOption.Manual)]
public class ResetSetting : IExternalCommand
{
#region IExternalCommand Members Implementation

public Autodesk.Revit.UI.Result Execute(ExternalCommandData revit,
ref string message,
ElementSet elements)
{
RibbonPanel myPanel = revit.Application.GetRibbonPanels()[0];
//reset wall type
RadioButtonGroup radioGroupTypeSelector =
GetRibbonItemByName(myPanel, "WallTypeSelector") as RadioButtonGroup;
if (null == radioGroupTypeSelector) { throw new InvalidCastException("Cannot get Wall Type selector!"); }
radioGroupTypeSelector.Current = radioGroupTypeSelector.GetItems()[0];

//reset level
Autodesk.Revit.UI.ComboBox comboboxLevel =
GetRibbonItemByName(myPanel, "LevelsSelector") as Autodesk.Revit.UI.ComboBox;
if (null == comboboxLevel) { throw new InvalidCastException("Cannot get Level selector!"); }
comboboxLevel.Current = comboboxLevel.GetItems()[0];

//reset wall shape
Autodesk.Revit.UI.ComboBox comboboxWallShape =
GetRibbonItemByName(myPanel, "WallShapeComboBox") as Autodesk.Revit.UI.ComboBox;
if (null == comboboxLevel) { throw new InvalidCastException("Cannot get wall shape combo box!"); }
comboboxWallShape.Current = comboboxWallShape.GetItems()[0];

//get wall mark
Autodesk.Revit.UI.TextBox textBox =
GetRibbonItemByName(myPanel, "WallMark") as Autodesk.Revit.UI.TextBox;
if (null == textBox) { throw new InvalidCastException("Cannot get Wall Mark TextBox!"); }
textBox.Value = "new wall";

return Autodesk.Revit.UI.Result.Succeeded;
}

/// <summary>
/// return the RibbonItem by the input name in a specific panel
/// </summary>
/// <param name="panelRibbon">RibbonPanel which contains the RibbonItem </param>
/// <param name="itemName">name of RibbonItem</param>
/// <return>RibbonItem whose name is same with input string</param>
public RibbonItem GetRibbonItemByName(RibbonPanel panelRibbon, String itemName)
{
foreach (RibbonItem item in panelRibbon.GetItems())
{
if (itemName == item.Name)
{
return item;
}
}

return null;
}

#endregion IExternalCommand Members Implementation
}

/// <summary>
/// Do Nothing,
/// Create this just because ToggleButton have to bind to a ExternalCommand
/// </summary>
[Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
[Autodesk.Revit.Attributes.Regeneration(Autodesk.Revit.Attributes.RegenerationOption.Manual)]
public class Dummy : IExternalCommand
{
#region IExternalCommand Members Implementation

public Autodesk.Revit.UI.Result Execute(ExternalCommandData revit,
ref string message,
ElementSet elements)
{
return Autodesk.Revit.UI.Result.Succeeded;
}

#endregion IExternalCommand Members Implementation
}
}

Ribbon.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 System.Linq;
using System.Text;
using Autodesk.Revit;
using System.Diagnostics;
using System.IO;
using System.Windows.Media;
using System.Windows.Forms;
using System.Windows.Media.Imaging;
using Autodesk.Revit.UI;
using Autodesk.Revit.DB;
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.UI.Events;

namespace Revit.SDK.Samples.Ribbon.CS
{
/// <summary>
/// Implements the Revit add-in interface IExternalApplication,
/// show user how to create RibbonItems by API in Revit.
/// we add one RibbonPanel:
/// 1. contains a SplitButton for user to create Non-Structural or Structural Wall;
/// 2. contains a StackedButton which is consisted with one PushButton and two Comboboxes,
/// PushButton is used to reset all the RibbonItem, Comboboxes are use to select Level and WallShape
/// 3. contains a RadioButtonGroup for user to select WallType.
/// 4. Adds a Slide-Out Panel to existing panel with following functionalities:
/// 5. a text box is added to set mark for new wall, mark is a instance parameter for wall,
/// Eg: if user set text as "wall", then Mark for each new wall will be "wall1", "wall2", "wall3"....
/// 6. a StackedButton which consisted of a PushButton (delete all the walls) and a PulldownButton (move all the walls in X or Y direction)
/// </summary>
[Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
[Autodesk.Revit.Attributes.Regeneration(Autodesk.Revit.Attributes.RegenerationOption.Manual)]
[Autodesk.Revit.Attributes.Journaling(Autodesk.Revit.Attributes.JournalingMode.NoCommandData)]
public class Ribbon : IExternalApplication
{
// ExternalCommands assembly path
static string AddInPath = typeof(Ribbon).Assembly.Location;
// Button icons directory
static string ButtonIconsFolder = Path.GetDirectoryName(AddInPath);
// uiApplication
static UIApplication uiApplication = null;

#region IExternalApplication Members
/// <summary>
/// Implement this method to implement the external application which should be called when
/// Revit starts before a file or default template is actually loaded.
/// </summary>
/// <param name="application">An object that is passed to the external application
/// which contains the controlled application.</param>
/// <returns>Return the status of the external application.
/// A result of Succeeded means that the external application successfully started.
/// Cancelled can be used to signify that the user cancelled the external operation at
/// some point.
/// If Failed is returned then Revit should inform the user that the external application
/// failed to load and the release the internal reference.</returns>
public Autodesk.Revit.UI.Result OnStartup(UIControlledApplication application)
{
try
{
// create customer Ribbon Items
CreateRibbonSamplePanel(application);

return Autodesk.Revit.UI.Result.Succeeded;
}
catch (Exception ex)
{
TaskDialog.Show("Ribbon Sample", ex.ToString());

return Autodesk.Revit.UI.Result.Failed;
}
}

/// <summary>
/// Implement this method to implement the external application which should be called when
/// Revit is about to exit, Any documents must have been closed before this method is called.
/// </summary>
/// <param name="application">An object that is passed to the external application
/// which contains the controlled application.</param>
/// <returns>Return the status of the external application.
/// A result of Succeeded means that the external application successfully shutdown.
/// Cancelled can be used to signify that the user cancelled the external operation at
/// some point.
/// If Failed is returned then the Revit user should be warned of the failure of the external
/// application to shut down correctly.</returns>
public Autodesk.Revit.UI.Result OnShutdown(UIControlledApplication application)
{
//remove events
List<RibbonPanel> myPanels = application.GetRibbonPanels();
Autodesk.Revit.UI.ComboBox comboboxLevel = (Autodesk.Revit.UI.ComboBox)(myPanels[0].GetItems()[2]);
application.ControlledApplication.DocumentCreated -= new EventHandler<
Autodesk.Revit.DB.Events.DocumentCreatedEventArgs>(DocumentCreated);
Autodesk.Revit.UI.TextBox textBox = myPanels[0].GetItems()[5] as Autodesk.Revit.UI.TextBox;
textBox.EnterPressed -= new EventHandler<
Autodesk.Revit.UI.Events.TextBoxEnterPressedEventArgs>(SetTextBoxValue);

return Autodesk.Revit.UI.Result.Succeeded;
}
#endregion

/// <summary>
/// This method is used to create RibbonSample panel, and add wall related command buttons to it:
/// 1. contains a SplitButton for user to create Non-Structural or Structural Wall;
/// 2. contains a StackedBotton which is consisted with one PushButton and two Comboboxes,
/// PushButon is used to reset all the RibbonItem, Comboboxes are use to select Level and WallShape
/// 3. contains a RadioButtonGroup for user to select WallType.
/// 4. Adds a Slide-Out Panel to existing panel with following functionalities:
/// 5. a text box is added to set mark for new wall, mark is a instance parameter for wall,
/// Eg: if user set text as "wall", then Mark for each new wall will be "wall1", "wall2", "wall3"....
/// 6. a StackedButton which consisted of a PushButton (delete all the walls) and a PulldownButton (move all the walls in X or Y direction)
/// </summary>
/// <param name="application">An object that is passed to the external application
/// which contains the controlled application.</param>
private void CreateRibbonSamplePanel(UIControlledApplication application)
{
// create a Ribbon panel which contains three stackable buttons and one single push button.
string firstPanelName = "Ribbon Sample";
RibbonPanel ribbonSamplePanel = application.CreateRibbonPanel(firstPanelName);

#region Create a SplitButton for user to create Non-Structural or Structural Wall
SplitButtonData splitButtonData = new SplitButtonData("NewWallSplit", "Create Wall");
SplitButton splitButton = ribbonSamplePanel.AddItem(splitButtonData) as SplitButton;
PushButton pushButton = splitButton.AddPushButton(new PushButtonData("WallPush", "Wall", AddInPath, "Revit.SDK.Samples.Ribbon.CS.CreateWall"));
pushButton.LargeImage = new BitmapImage(new Uri(Path.Combine(ButtonIconsFolder, "CreateWall.png"), UriKind.Absolute));
pushButton.Image = new BitmapImage(new Uri(Path.Combine(ButtonIconsFolder, "CreateWall-S.png"), UriKind.Absolute));
pushButton.ToolTip = "Creates a partition wall in the building model.";
pushButton.ToolTipImage = new BitmapImage(new Uri(Path.Combine(ButtonIconsFolder, "CreateWallTooltip.bmp"), UriKind.Absolute));
pushButton = splitButton.AddPushButton(new PushButtonData("StrWallPush", "Structure Wall", AddInPath, "Revit.SDK.Samples.Ribbon.CS.CreateStructureWall"));
pushButton.LargeImage = new BitmapImage(new Uri(Path.Combine(ButtonIconsFolder, "StrcturalWall.png"), UriKind.Absolute));
pushButton.Image = new BitmapImage(new Uri(Path.Combine(ButtonIconsFolder, "StrcturalWall-S.png"), UriKind.Absolute));
#endregion

ribbonSamplePanel.AddSeparator();

#region Add a StackedButton which is consisted of one PushButton and two Comboboxes
PushButtonData pushButtonData = new PushButtonData("Reset", "Reset", AddInPath, "Revit.SDK.Samples.Ribbon.CS.ResetSetting");
ComboBoxData comboBoxDataLevel = new ComboBoxData("LevelsSelector");
ComboBoxData comboBoxDataShape = new ComboBoxData("WallShapeComboBox");
IList<RibbonItem> ribbonItemsStacked = ribbonSamplePanel.AddStackedItems(pushButtonData, comboBoxDataLevel, comboBoxDataShape);
((PushButton)(ribbonItemsStacked[0])).Image = new BitmapImage(new Uri(Path.Combine(ButtonIconsFolder, "Reset.png"), UriKind.Absolute));
//Add options to WallShapeComboBox
Autodesk.Revit.UI.ComboBox comboboxWallShape = (Autodesk.Revit.UI.ComboBox)(ribbonItemsStacked[2]);
ComboBoxMemberData comboBoxMemberData = new ComboBoxMemberData("RectangleWall", "RectangleWall");
ComboBoxMember comboboxMember = comboboxWallShape.AddItem(comboBoxMemberData);
comboboxMember.Image = new BitmapImage(new Uri(Path.Combine(ButtonIconsFolder, "RectangleWall.png"), UriKind.Absolute));
comboBoxMemberData = new ComboBoxMemberData("CircleWall", "CircleWall");
comboboxMember = comboboxWallShape.AddItem(comboBoxMemberData);
comboboxMember.Image = new BitmapImage(new Uri(Path.Combine(ButtonIconsFolder, "CircleWall.png"), UriKind.Absolute));
comboBoxMemberData = new ComboBoxMemberData("TriangleWall", "TriangleWall");
comboboxMember = comboboxWallShape.AddItem(comboBoxMemberData);
comboboxMember.Image = new BitmapImage(new Uri(Path.Combine(ButtonIconsFolder, "TriangleWall.png"), UriKind.Absolute));
comboBoxMemberData = new ComboBoxMemberData("SquareWall", "SquareWall");
comboboxMember = comboboxWallShape.AddItem(comboBoxMemberData);
comboboxMember.Image = new BitmapImage(new Uri(Path.Combine(ButtonIconsFolder, "SquareWall.png"), UriKind.Absolute));
#endregion

ribbonSamplePanel.AddSeparator();

#region Add a RadioButtonGroup for user to select WallType
RadioButtonGroupData radioButtonGroupData = new RadioButtonGroupData("WallTypeSelector");
RadioButtonGroup radioButtonGroup = (RadioButtonGroup)(ribbonSamplePanel.AddItem(radioButtonGroupData));
ToggleButton toggleButton = radioButtonGroup.AddItem(new ToggleButtonData("Generic8", "Generic - 8\"", AddInPath, "Revit.SDK.Samples.Ribbon.CS.Dummy"));
toggleButton.LargeImage = new BitmapImage(new Uri(Path.Combine(ButtonIconsFolder, "Generic8.png"), UriKind.Absolute));
toggleButton.Image = new BitmapImage(new Uri(Path.Combine(ButtonIconsFolder, "Generic8-S.png"), UriKind.Absolute));
toggleButton = radioButtonGroup.AddItem(new ToggleButtonData("ExteriorBrick", "Exterior - Brick", AddInPath, "Revit.SDK.Samples.Ribbon.CS.Dummy"));
toggleButton.LargeImage = new BitmapImage(new Uri(Path.Combine(ButtonIconsFolder, "ExteriorBrick.png"), UriKind.Absolute));
toggleButton.Image = new BitmapImage(new Uri(Path.Combine(ButtonIconsFolder, "ExteriorBrick-S.png"), UriKind.Absolute));
#endregion

//slide-out panel:
ribbonSamplePanel.AddSlideOut();

#region add a Text box to set the mark for new wall
TextBoxData testBoxData = new TextBoxData("WallMark");
Autodesk.Revit.UI.TextBox textBox = (Autodesk.Revit.UI.TextBox)(ribbonSamplePanel.AddItem(testBoxData));
textBox.Value = "new wall"; //default wall mark
textBox.Image = new BitmapImage(new Uri(Path.Combine(ButtonIconsFolder, "WallMark.png"), UriKind.Absolute));
textBox.ToolTip = "Set the mark for new wall";
textBox.ShowImageAsButton = true;
textBox.EnterPressed += new EventHandler<Autodesk.Revit.UI.Events.TextBoxEnterPressedEventArgs>(SetTextBoxValue);
#endregion

ribbonSamplePanel.AddSeparator();

#region Create a StackedButton which consisted of a PushButton (delete all the walls) and a PulldownButton (move all the walls in X or Y direction)
PushButtonData deleteWallsButtonData = new PushButtonData("deleteWalls", "Delete Walls", AddInPath, "Revit.SDK.Samples.Ribbon.CS.DeleteWalls");
deleteWallsButtonData.ToolTip = "Delete all the walls created by the Create Wall tool.";
deleteWallsButtonData.Image = new BitmapImage(new Uri(Path.Combine(ButtonIconsFolder, "DeleteWalls.png"), UriKind.Absolute));

PulldownButtonData moveWallsButtonData = new PulldownButtonData("moveWalls", "Move Walls");
moveWallsButtonData.ToolTip = "Move all the walls in X or Y direction";
moveWallsButtonData.Image = new BitmapImage(new Uri(Path.Combine(ButtonIconsFolder, "MoveWalls.png"), UriKind.Absolute));

// create stackable buttons
IList<RibbonItem> ribbonItems = ribbonSamplePanel.AddStackedItems(deleteWallsButtonData, moveWallsButtonData);

// add two push buttons as sub-items of the moveWalls PulldownButton.
PulldownButton moveWallItem = ribbonItems[1] as PulldownButton;

PushButton moveX = moveWallItem.AddPushButton(new PushButtonData("XDirection", "X Direction", AddInPath, "Revit.SDK.Samples.Ribbon.CS.XMoveWalls"));
moveX.ToolTip = "move all walls 10 feet in X direction.";
moveX.LargeImage = new BitmapImage(new Uri(Path.Combine(ButtonIconsFolder, "MoveWallsXLarge.png"), UriKind.Absolute));

PushButton moveY = moveWallItem.AddPushButton(new PushButtonData("YDirection", "Y Direction", AddInPath, "Revit.SDK.Samples.Ribbon.CS.YMoveWalls"));
moveY.ToolTip = "move all walls 10 feet in Y direction.";
moveY.LargeImage = new BitmapImage(new Uri(Path.Combine(ButtonIconsFolder, "MoveWallsYLarge.png"), UriKind.Absolute));
#endregion

ribbonSamplePanel.AddSeparator();

application.ControlledApplication.DocumentCreated += new EventHandler<Autodesk.Revit.DB.Events.DocumentCreatedEventArgs>(DocumentCreated);
}

/// <summary>
/// Insert Level into ComboBox - LevelsSelector
/// </summary>
/// <param name="evnetArgs">Autodesk.Revit.DB.Events.DocumentCreatedEventArgs</param>
public void DocumentCreated(object sender, Autodesk.Revit.DB.Events.DocumentCreatedEventArgs e)
{
uiApplication = new UIApplication(e.Document.Application);
List<RibbonPanel> myPanels = uiApplication.GetRibbonPanels();

Autodesk.Revit.UI.ComboBox comboboxLevel = (Autodesk.Revit.UI.ComboBox)(myPanels[0].GetItems()[2]);
if (null == comboboxLevel) { return; }
FilteredElementCollector collector = new FilteredElementCollector(uiApplication.ActiveUIDocument.Document);
ICollection<Element> founds = collector.OfClass(typeof(Level)).ToElements();
foreach (Element elem in founds)
{
Level level = elem as Level;
ComboBoxMemberData comboBoxMemberData = new ComboBoxMemberData(level.Name, level.Name);
ComboBoxMember comboboxMember = comboboxLevel.AddItem(comboBoxMemberData);
comboboxMember.Image = new BitmapImage(new Uri(Path.Combine(ButtonIconsFolder, "LevelsSelector.png"), UriKind.Absolute));
}
//refresh level list (in case user created new level after document created)
comboboxLevel.DropDownOpened += new EventHandler<ComboBoxDropDownOpenedEventArgs>(AddNewLevels);
}

/// <summary>
/// Bind to combobox's DropDownOpened Event, add new levels that created by user.
/// </summary>
/// <param name="evnetArgs">Autodesk.Revit.UI.Events.ComboBoxDropDownOpenedEventArgs</param>
public void AddNewLevels(object sender, ComboBoxDropDownOpenedEventArgs args)
{
Autodesk.Revit.UI.ComboBox comboboxLevel = sender as Autodesk.Revit.UI.ComboBox;
if (null == comboboxLevel) { return; }
FilteredElementCollector collector = new FilteredElementCollector(uiApplication.ActiveUIDocument.Document);
ICollection<Element> founds = collector.OfClass(typeof(Level)).ToElements();
foreach (Element elem in founds)
{
Level level = elem as Level;
bool alreadyContained = false;
foreach (ComboBoxMember comboboxMember in comboboxLevel.GetItems())
{
if (comboboxMember.Name == level.Name)
{
alreadyContained = true;
}
}
if (!alreadyContained)
{
ComboBoxMemberData comboBoxMemberData = new ComboBoxMemberData(level.Name, level.Name);
ComboBoxMember comboboxMember = comboboxLevel.AddItem(comboBoxMemberData);
comboboxMember.Image = new BitmapImage(new Uri(Path.Combine(ButtonIconsFolder, "LevelsSelector.png"), UriKind.Absolute));
}
}

}

/// <summary>
/// Bind to text box's EnterPressed Event, show a dialogue tells user value of test box changed.
/// </summary>
/// <param name="evnetArgs">Autodesk.Revit.UI.Events.TextBoxEnterPressedEventArgs</param>
public void SetTextBoxValue(object sender, TextBoxEnterPressedEventArgs args)
{
TaskDialog.Show("TextBox EnterPressed Event", "New wall's mark changed.");
}

}
}