Revit API Developer's Guide MD 변환본 추가 (368 페이지)

Revit 2026 공식 Developer's Guide HTML → MD 변환.
Output/revit-api-guide/에 8개 카테고리 폴더로 정리.
CLAUDE.md에 참조 규칙 추가, .gitignore에 .scratch/ 제외.

소스: help.autodesk.com/view/RVT/2026/ENU (CC BY-NC-SA 3.0)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
minsung
2026-04-14 17:33:42 +09:00
parent 3bd01e31c9
commit b4a8714793
370 changed files with 28908 additions and 0 deletions

3
.gitignore vendored
View File

@@ -27,3 +27,6 @@ raw/
# Default Obsidian welcome note # Default Obsidian welcome note
환영합니다!.md 환영합니다!.md
# Scratch / temp scripts
.scratch/

View File

@@ -63,3 +63,19 @@ cimery 관련 작업 시작 시 `cimery-dev-guide.md`를 먼저 읽을 것. ADR
10. `index.md` 항목은 한 줄, 120자 이내. 10. `index.md` 항목은 한 줄, 120자 이내.
각 폴더 세부 규칙은 해당 폴더의 `CLAUDE.md` 참조. 각 폴더 세부 규칙은 해당 폴더의 `CLAUDE.md` 참조.
## 참조 자료: Revit API Developer's Guide
`Output/revit-api-guide/` — Revit 2026 공식 Developer's Guide 전체(368 페이지) MD 변환본. wiki 편입 전 단계.
**폴더 구조:**
- `Introduction/` — 기본 개념, Add-in 등록, Hello World
- `Basic Interaction with Revit Elements/` — Element, Parameter, Filter, Selection 핵심
- `Revit Geometric Elements/` — Geometry, Solid, Curve, Face, Transform
- `Discipline-Specific Functionality/` — Structures(구조), MEP, Architectural
- `Advanced Topics/` — Transaction, Dynamic Model Update, Events
- `Appendices/` — 코드 컨벤션, 기타
**참조 규칙:**
- cimery 개발 중 Revit API 개념 필요 시 `obsidian search:context query="..."` 또는 `Grep path="Output/revit-api-guide"` 로 검색.
- 자주 참조되는 페이지는 wiki/ 로 승격 (ingest-raw 아닌 수동 선별).

View File

@@ -0,0 +1,71 @@
# Analysis Results Display
# Analysis Results Display
The AnalysisDisplayStyle class can be used to control how the analysis results are displayed in the view. The static CreateAnalysisDisplayStyle() method can create either a colored surface display style, a markers with text style, a deformed shape style, diagram style or vector style. For any style, the color and legend settings can also be set.
Once a new AnalysisDisplayStyle is created, use the View.AnalysisDisplayStyleId to assign the style to a view. Although the analysis results are not saved with the document, analysis display styles and their assignment to a view are saved with the model.
|
---|---
**_"Colored surface" Display Style_** | **_"Markers with text" Display Style_**
The following example creates a new colored surface analysis display style (if not already found in the document) and then assigns it to the current view.
**Code Region 27-2: Setting analysis display style for view**
---
public void SetDisplayStyle(Document doc)
{
AnalysisDisplayStyle analysisDisplayStyle = null;
// Look for an existing analysis display style with a specific name
FilteredElementCollector collector1 = new FilteredElementCollector(doc);
ICollection<Element> collection =
collector1.OfClass(typeof(AnalysisDisplayStyle)).ToElements();
var displayStyle = from element in collection
where element.Name == "Display Style 1"
select element;
// If display style does not already exist in the document, create it
if (displayStyle.Count() == 0)
{
AnalysisDisplayColoredSurfaceSettings coloredSurfaceSettings = new AnalysisDisplayColoredSurfaceSettings();
coloredSurfaceSettings.ShowGridLines = true;
AnalysisDisplayColorSettings colorSettings = new AnalysisDisplayColorSettings();
Color orange = new Color(255, 205, 0);
Color purple = new Color(200, 0, 200);
colorSettings.MaxColor = orange;
colorSettings.MinColor = purple;
AnalysisDisplayLegendSettings legendSettings = new AnalysisDisplayLegendSettings();
legendSettings.NumberOfSteps = 10;
legendSettings.Rounding = 0.05;
legendSettings.ShowDataDescription = false;
legendSettings.ShowLegend = true;
FilteredElementCollector collector2 = new FilteredElementCollector(doc);
ICollection<Element> elementCollection = collector2.OfClass(typeof(TextNoteType)).ToElements();
var textElements = from element in collector2
where element.Name == "LegendText"
select element;
// if LegendText exists, use it for this Display Style
if (textElements.Count() > 0)
{
TextNoteType textType =
textElements.Cast<TextNoteType>().ElementAt<TextNoteType>(0);
legendSettings.TextTypeId = textType.Id;
}
analysisDisplayStyle = AnalysisDisplayStyle.CreateAnalysisDisplayStyle(doc, "Display Style 1", coloredSurfaceSettings, colorSettings, legendSettings);
}
else
{
analysisDisplayStyle =
displayStyle.Cast<AnalysisDisplayStyle>().ElementAt<AnalysisDisplayStyle>(0);
}
// now assign the display style to the view
doc.ActiveView.AnalysisDisplayStyleId = analysisDisplayStyle.Id;
}
**Parent page:** [Analysis Visualization](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Analysis_Analysis_Visualization_html.html)

View File

@@ -0,0 +1,52 @@
# Creating Analysis Results Data
# Creating Analysis Results Data
Once a primitive has been added to the SpatialFieldManager, analysis results can be created and added to the analysis results container using the UpdateSpatialFieldPrimitive() method. This method takes a set of domain points (FieldDomainPoints) where results are calculated and a set of values (FieldValues) for each point. The number of FieldValues must correspond to the number of domain points. However, each domain point can have an array of values, each for a separate measurement at this point.
The following example creates a simple set of analysis results on an element face selected by the user. The SDK sample SpatialFieldGradient demonstrates a more complex use case where each point has multiple associated values.
**Code Region 27-1: Creating Analysis Results**
---
public void CreateAnalysisResults(UIDocument uidoc)
{
Document doc = uidoc.Document;
SpatialFieldManager sfm = SpatialFieldManager.GetSpatialFieldManager(doc.ActiveView);
if (null == sfm)
{
sfm = SpatialFieldManager.CreateSpatialFieldManager(doc.ActiveView, 1);
}
Reference reference = uidoc.Selection.PickObject(ObjectType.Face, "Select a face");
int idx = sfm.AddSpatialFieldPrimitive(reference);
Face face = doc.GetElement(reference).GetGeometryObjectFromReference(reference) as Face;
IList<UV> uvPts = new List<UV>();
BoundingBoxUV bb = face.GetBoundingBox();
UV min = bb.Min;
UV max = bb.Max;
uvPts.Add(new UV(min.U,min.V));
uvPts.Add(new UV(max.U,max.V));
FieldDomainPointsByUV pnts = new FieldDomainPointsByUV(uvPts);
List<double> doubleList = new List<double>();
IList<ValueAtPoint> valList = new List<ValueAtPoint>();
doubleList.Add(0);
valList.Add(new ValueAtPoint(doubleList));
doubleList.Clear();
doubleList.Add(10);
valList.Add(new ValueAtPoint(doubleList));
FieldValues vals = new FieldValues(valList);
AnalysisResultSchema resultSchema = new AnalysisResultSchema("Schema Name", "Description");
int schemaIndex = sfm.RegisterResult(resultSchema);
sfm.UpdateSpatialFieldPrimitive(idx, pnts, vals, schemaIndex);
}
**Parent page:** [Analysis Visualization](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Analysis_Analysis_Visualization_html.html)

View File

@@ -0,0 +1,46 @@
# Manager for Analysis Results
# Manager for Analysis Results
A new SpatialFieldManager can be added to a view using the static SpatialFieldManager.CreateSpatialFieldManager() method. Only one manager can be associated with a view. If a view already has a SpatialFieldManager, it can be retrieved with the static method GetSpatialFieldManager().
CreateSpatialFieldManager() takes a parameter for the number of measurements that will be calculated for each point. This number defines how many results values will be associated with each point at which results are calculated. For example, if average solar radiation is computed for every month of the year, each point would have 12 corresponding values.
To add analysis results to the view, call AddSpatialFieldPrimitive() to create a new analysis results container. Four overloads of this method exist to create primitives associated with:
* A Reference (to a curve or a face)
* A curve and a transform
* A face and a transform
* No Revit geometry - To improve performance when creating many data points that are not related to Revit geometry, it is recommended to create multiple primitives with no more than 500 points each instead of one large primitive containing all points.
A typical use of the transform overloads will be to locate the results data offset from geometry in the Revit model, for example, 3 feet above a floor.
The AddSpatialFieldPrimitive() method returns a unique integer identifier of the primitive within the SpatialFieldManager, which can later be used to identify the primitive to remove it (RemoveSpatialFieldPrimitive()) or to modify the primitive (UpdateSpatialFieldPrimitive()).
Note that the AddSpatialFieldPrimitive() method creates an empty analysis results primitive. UpdateSpatialFieldPrimitive() must be called in order populate the analysis results data with points and values as shown in the [Creating Analysis Results Data](./Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Analysis_Analysis_Visualization_Creating_analysis_results_data_html.html) section.
The UpdateSpatialFieldPrimitive() method requires the unique index of an AnalysisResultSchema that has been registered with the SpatialFieldManager. An AnalysisResultSchema holds information about an analysis results, such as a name, description and the names and multipliers of all units for result visualization. The following example demonstrates how to create a new AnalysisResultSchema and set its units.
**Code Region: AnalysisResultsSchema**
---
private void CreateSchema()
{
IList<string> unitNames = new List<string>();
unitNames.Add("Feet");
unitNames.Add("Inches");
IList<double> multipliers = new List<double>();
multipliers.Add(1);
multipliers.Add(12);
AnalysisResultSchema resultSchema = new AnalysisResultSchema("Schema Name", "Description");
resultSchema.SetUnits(unitNames, multipliers);
}
Once the AnalysisResultschema is configured, it needs to be registered using the SpatialFieldManager.RegisterResult() method, which will return a unique index for the result. Use GetResultSchema() and SetResultSchema() using this unique index to get and change the result after it has been registered.
**Parent page:** [Analysis Visualization](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Analysis_Analysis_Visualization_html.html)

View File

@@ -0,0 +1,9 @@
# Updating Analysis Results
# Updating Analysis Results
The Revit analysis framework does not update results automatically, and potentially any change to Revit model can invalidate results.
In order to keep results up to date, API developers should use [Dynamic Model Update](../../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Dynamic_Model_Update_html.html) triggers or subscribe to the [DocumentChanged event](../../Events/Database_Events/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Events_Database_Events_DocumentChanged_event_html.html) to be notified when the Revit model has changed and previously calculated results may be invalid and in need of recalculation. For an example showing Dynamic Model Update together with Analysis Visualization, see the DistanceToSurfaces sample in the Revit SDK.
**Parent page:** [Analysis Visualization](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Analysis_Analysis_Visualization_html.html)

View File

@@ -0,0 +1,72 @@
# Analysis Visualization
# Analysis Visualization
The Revit API provides a mechanism for external analysis applications to easily display the results of their computation in the Revit model. The SpatialFieldManager class is the main class for communicating analysis results back to Revit. It is used to create, delete, and modify the "containers" in which the analysis results are stored. The AnalysisResultSchema class contains all information about one analysis result, such as a description and the names and multipliers of all units for result visualization. Multiple AnalysisResultSchemas can be registered with the SpatialFieldManager.
The AnalysisDisplayStyle class can then be used to control the appearance of the results. Creation and modification of AnalysisDisplayStyle from a plug-in is optional; end users can have the same control over the presentation of the analysis results with the Revit UI.
The data model supported by Revit API requires that analysis results are specified at a certain set of points, and that at each point one or more distinct numbers ("measurements") are computed. The number of measurements must be the same at all model points. The results data is transient; it is stored only in the model until the document is closed. If the model is saved, closed, and reopened the analysis results will not be present.
## Framework Overview
The Analysis Visualization Framework (AVF) enables the display of external calculations in the context of a Revit model. API users do not have to know the details of internal Revit drawing mechanism; all they need to do is (a) to populate correctly data containers with calculated numbers representing the calculated properties and (b) to specify the Revit View and style of the data display. Calculated numbers should represent a certain Spatial Field (function) defined on the Field Domain with the corresponding Field Values.
### Field Domain
Field Domain is an array of points that can be defined in any of the following layouts:
* along a curve (one-dimensional), API class FieldDomainPointsByParameter;
* on a surface (two-dimensional), API class FieldDomainPointsByUV;
* in space (three-dimensional), API class FieldDomainPointsByXYZ.
These classes have a common base class FieldDomainPoints.
### Field Values
Field Values is an array of scalar or vector values calculated at each domain point. The corresponding API class is FieldValues. It can be constructed by taking an input array of ValueAtPoint or VectorAtPoint objects. The size of these arrays must be equal to the size of array of points in the corresponding FieldDomainPoints object.
Each ValueAtPoint or VectorAtPoint object can contain one or more measurements calculated at the same point in Field Domain. The restriction is that the number of measurements must be the same for each point in Field Domain (see Figure 1 below).
Each measurement can have a name and a description (see SpatialFieldManager.SetMeasurementNames() and SpatialFieldManager.SetMeasurementDescriptions()). Only one measurement is displayed at a time in Revit View (see SpatialFieldManager.CurrentMeasurement property).
### Spatial Field Primitive
Spatial Field Primitive represents the pairing of FieldDomainPoints and its corresponding FieldValues (see Figure 1 below). Each primitive:
* can be associated with a Reference to a Curve or Surface in Revit model geometry (corresponding FieldDomainPointsByParameter or FieldDomainPointsByUV must be used);
* can be associated with a Curve or Surface (constructed on demand by API user) that are not part of Revit geometry (corresponding FieldDomainPointsByParameter or FieldDomainPointsByUV must be used);
* can represent free points in space (corresponding FieldDomainPointsByXYZ must be used);
Field Domain | Point [1] | Point [2] | ... | Point [N-1] | Point [N]
---|---|---|---|---|---
Field Values | ValueAtPoint [1] | ValueAtPoint[2] | ... | ValueAtPoint[N-1] | ValueAtPoint[N]
measurement [1] | Value [1,1] | Value [2,1] | ... | Value [N-1,1] | Value [N,1]
measurement [2] | Value [1,2] | Value [2,2] | ... | Value [N-1,2] | Value [N,2]
... | ... | ... | ... | ... | ...
measurement [i] | | | | |
currently displayed | Value [1,i] | Value [2,i] | ... | Value [N-1,i] | Value [N,i]
... | ... | ... | ... | ... | ...
measurement [M-1] | Value [1,M-1] | Value [2,M-1] | ... | Value [N-1,M-1] | Value [N,M-1]
measurement [M] | Value [1,M] | Value [2,M] | ... | Value [N-1,M] | Value [N,M]
**Figure 1. Spatial Field Primitive with N domain points and M measurements.**
Each Spatial Field (can also be called a Result) consists of a set of Spatial Field Primitives (see SpatialFieldManager.AddSpatialFieldPrimitive() and SpatialFieldManager.UpdateSpatialFieldPrimitive()).
### Result
Result represents a set of Spatial Field Primitives corresponding to a particular Spatial Field. Each Result can have a name, description, units, etc. (see AnalysisResultSchema). A number of Results can be displayed in a particular Revit View (see SpatialFieldManager.RegisterResult() and SpatialFieldManagerGetRegisteredResults()). All Results in the same View must have the same number of measurements (see SpatialFieldManager.NumberOfMeasurements property).
**Pages in this section**
* [Manager for Analysis Results](Analysis_Visualization/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Analysis_Analysis_Visualization_Manager_for_analysis_results_html.html)
* [Creating Analysis Results Data](Analysis_Visualization/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Analysis_Analysis_Visualization_Creating_analysis_results_data_html.html)
* [Analysis Results Display](Analysis_Visualization/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Analysis_Analysis_Visualization_Analysis_Results_Display_html.html)
* [Updating Analysis Results](Analysis_Visualization/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Analysis_Analysis_Visualization_Updating_Analysis_Results_html.html)
**Parent page:** [Analysis](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Analysis_html.html)

View File

@@ -0,0 +1,160 @@
# Detailed Energy Analysis Model
# Detailed Energy Analysis Model
The Autodesk.Revit.DB.Analysis namespace includes several classes to obtain and analyze the contents of a project's detailed energy analysis model.
The Export to gbXML and the Heating and Cooling Loads features produce an analytical thermal model from the physical model of a building. The analytical thermal model is composed of spaces, zones and planar surfaces that represent the actual volumetric elements of the building.
The classes related to the detailed energy analysis model are:
* EnergyAnalysisDetailModel
* EnergyAnalysisDetailModelOptions
* EnergyAnalysisOpening
* EnergyAnalysisSpace
* EnergyAnalysisSurface
* Polyloop
The following read-only properties are available for access to zone analysis properties:
* EnergyAnalysisZone.HeatingSetPoint
* EnergyAnalysisZone.CoolingSetPoint
* EnergyAnalysisZone.UseHumidificationSetPoint
* EnergyAnalysisZone.UseDehumidificationSetPoint
* EnergyAnalysisZone.HumidificationSetPoint
* EnergyAnalysisZone.DehumidificationSetPoint
* EnergyAnalysisZone.OutsideAirPerPerson
* EnergyAnalysisZone.UseOutsideAirPerPerson
* EnergyAnalysisZone.OutsideAirPerArea
* EnergyAnalysisZone.UseOutsideAirPerArea
* EnergyAnalysisZone.AirChangesPerHour
* EnergyAnalysisZone.UseAirChangesPerHour
* EnergyAnalysisZone.CADObjectUniqueId
## Energy analysis model creation
Use the static method EnergyAnalysisDetailModel.Create() to create and populate the energy analysis model. The EnergyAnaysisDetailModel is stored as an element in the Revit model, and thus the EnergyAnalysisDetailModel.Create() method requires there to be an open transaction. The generated model is always returned in world coordinates, but the method TransformModel() transforms all surfaces in the model according to ground plane, shared coordinates and true north.
If an energy analysis model is already created, the static method EnergyAnalysisDetailModel.GetMainEnergyAnalysisDetailModel() returns the main EnergyAnalysisDetailModel contained in the given document (or null if none has been created). The energy analysis detail model can be displayed in associated views.
Set the appropriate options using the EnergyAnalysisDetailModelOptions class.
The options available when creating the energy analysis detail model include:
* The level of computation for energy analysis model - NotComputed, FirstLevelBoundaries, meaning analytical spaces and zones, SecondLevelBoundaries, meaning analytical surfaces, or Final, meaning constructions, schedules, and non-graphical data
* Whether the energy model is based on rooms/spaces or building elements
* Whether mullions should be exported as shading surfaces
* Whether shading surfaces will be included
* Whether to simplify curtain systems - When true, a single large window/opening will be exported for a curtain wall/system regardless of the number of panels in the system
The EnergyAnalysisDetailModelOptions.EnergyModelType property can be set to SpatialElement (where the energy model is based on rooms or spaces) or BuildingElement (where the energy model is based on analysis of building element volumes). However, note that the generated energy model is also affected by settings in EnergyDataSettings, including the EnergyDataSettings.AnalysisType property. If this property is set to AnalysisMode.ConceptualMassesAndBuildingElements, the EnergyAnalysisDetailModel will use the combination of conceptual masses and building elements.
The following example creates a new energy analysis detailed model from the physical model then displays the originating element for each surface of each space in the model.
**Code Region: Energy Analysis Detail Model**
---
public void GetThermalModelData(Document doc)
{
// Collect space and surface data from the building's analytical thermal model
EnergyAnalysisDetailModelOptions options = new EnergyAnalysisDetailModelOptions();
options.Tier = EnergyAnalysisDetailModelTier.Final; // include constructions, schedules, and non-graphical data in the computation of the energy analysis model
options.EnergyModelType = EnergyModelType.SpatialElement; // Energy model based on rooms or spaces
EnergyAnalysisDetailModel eadm = EnergyAnalysisDetailModel.Create(doc, options); // Create a new energy analysis detailed model from the physical model
IList<EnergyAnalysisSpace> spaces = eadm.GetAnalyticalSpaces();
StringBuilder builder = new StringBuilder();
builder.AppendLine("Spaces: " + spaces.Count);
foreach (EnergyAnalysisSpace space in spaces)
{
SpatialElement spatialElement = doc.GetElement(space.CADObjectUniqueId) as SpatialElement;
ElementId spatialElementId = spatialElement == null ? ElementId.InvalidElementId : spatialElement.Id;
builder.AppendLine(" >>> " + space.SpaceName + " related to " + spatialElementId);
IList<EnergyAnalysisSurface> surfaces = space.GetAnalyticalSurfaces();
builder.AppendLine(" has " + surfaces.Count + " surfaces.");
foreach (EnergyAnalysisSurface surface in surfaces)
{
builder.AppendLine(" +++ Surface from " + surface.OriginatingElementDescription);
}
}
TaskDialog.Show("EAM", builder.ToString());
}
After creating the EnergyAnalysisDetailModel, the spaces, openings and surfaces associated with it can be retrieved with the GetAnalyticalOpenings(), GetAnalyticalSpaces(), GetAnalyticalShadingSurfaces() and GetAnalyticalSurfaces() methods.
It is recommended that applications call Document.Delete() on the EnergyAnalysisDetailModel elements that they create when finished accessing the data, but any energy models created after the main energy model will be deleted automatically before document saving or synchronization.
## EnergyAnalysisSpace
From an EnergyAnalysisSpace you can retrieve the collection of EnergyAnalysisSurfaces which define an enclosed volume bounded by the center plane of walls and the top plane of roofs and floors. Alternatively, GetClosedShell() retrieves a collection of Polyloops, which are planar polygons, that define an enclosed volume measured by interior bounding surfaces. For two-dimensions, use GetBoundary() which returns a collection of Polyloops representing the 2D boundary of the space that defines an enclosed area measured by interior bounding surfaces.
The EnergyAnalysisSpace class also has a number of properties for accessing information about the analysis space, such as AnalyticalVolume, SpaceName and Area.
## EnergyAnalysisSurface
From an EnergyAnalysisSpace you can retrieve the primary analysis space associated with the surface as well as the secondary adjacent analytical space. The GetAnalyticalOpenings() method will retrieve a collection of all analytical openings in the surface. The GetPolyloop() method obtains the planar polygon describing the surface geometry as described in gbXML.
The EnergyAnalysisSurface class has numerous properties to provide more information about the analytical surface, such as Height, Width, Corner (lower-left coordinate for the analytical rectangular geometry viewed from outside), and an originating element description.
Use these properties to identify the originating Revit element's id and name:
* EnergyAnalysisSurface.OriginatingElementId
* EnergyAnalysisSurface.OriginatingElementName
The method EnergyAnalysisSurface.GetConstruction() allows users to get the analytic construction this surface is associated with.
The surface type is available either as an EnergyAnalysisSurfaceType or as a gbXMLSurfaceType. The gbXML surface type attribute is determined by the source element and the number of space adjacencies. Possible types are:
**Type** | **Source element and space adjacencies**
---|---
_Shade_ | No associated source element and no space adjacencies
_Air_ | No associated source element and at least one space adjacency
_ExteriorWall_ | Source element is a Wall or a Curtain Wall there is one space adjacency
_InteriorWall_ | Source element is a Wall or a Curtain Wall and: there are two space adjacencies or the type Function parameter is set to "Interior" or "CoreShaft"
_UndergroundWall_ | Source element is a Wall or a Curtain Wall and there is one space adjacency and if it is below grade
_SlabOnGrade_ | Source element is a Floor and there is one space adjacency
_RaisedFloor_ | Source element is a Floor and there is one space adjacency and it is above grade
_UndergroundSlab_ | Source element is a Floor and there is one space adjacency and it is below grade
_InteriorFloor_ | Source element is a Floor and: there are two space adjacencies or the type Function parameter is set to "Interior
_Roof_ | Source element is a Roof or a Ceiling and there is one space adjacency
_UndergroundCeiling_ | Source element is a Roof or a Ceiling and there is one space adjacency and it is below grade
_Ceiling_ | Source element is a Roof or a Ceiling and there are two space adjacencies
### Thermal Properties for Analytical Surfaces
Several classes in the Autodesk.Revit.DB.Analysis namespace allow users to retrieve thermal properties and material layers for analytical constructions and window types associated with analytical surfaces in the energy model. All thermal properties on EnergyAnalysisConstruction and EnergyAnalysisMaterial are read-only.
`EnergyAnalysisZone` \- Represents the analytical zone. EnergyAnalysisZone is associated with EnergyAnalysisSpace, and each EnergyAnalysisZone may be associated with one or more EnergyAnalysisSpace elements.
`EnergyAnalysisConstruction` \- Represents an analytical construction as a composite of layered materials and is generally associated with EnergyAnalysisSurface.
`EnergyAnalysisWindowType` \- Represents an analytical construction containing window type data and is assoicated with EnergyAnalysisOpening.
`EnergyAnalysisMaterial` \- Represents the description of a material with thermal properties in a composite construction.
The energy analysis enumerated types `gbXMLSurfaceType` and `ConstructionType` have values for a given element that can be retrieved for using the `EnergyAnalysisSurface.Type` and `EnergyAnalysisOpening.Type` properties.
## EnergyAnalysisOpening
From an EnergyAnalysisOpening you can retrieve the associated parent analytical surface element. The GetPolyloop() method returns the opening geometry as a planar polygon.
A number of properties are available to obtain information about the analytical opening, such as Height, Width, Corner and OpeningName. Similar as for analytical surfaces, the analytical opening type can be obtained as a simple EnergyAnalysisOpeningType enumeration or as a gbXMLOpeningType attribute. The type of the opening is based on the family category for the opening and in what element it is contained, as shown in the following table:
**Type** | **Family Category or containing element**
---|---
_OperableWindow_ | Window
_NonSlidingDoor_ | Door
_FixedSkylight_ | Opening contained in a Roof
_FixedWindow_ | Opening contained in a Curtain Wall Panel
_Air_ | Opening of the category Openings
**Parent page:** [Analysis](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Analysis_html.html)

View File

@@ -0,0 +1,27 @@
# Energy Data
# Energy Data
The EnergyDataSettings object contains settings for gbXML Export and Heating and Cooling Load Calculations and project level settings for Conceptual Energy Analysis.
The EnergyDataSettings object is derived from the Element base object. It is unique in each project, similar to ProjectInformation. Though EnergyDataSettings is a subclass of the Element class, most of the members inherited from the Element return null or an empty set except for Name, Id, UniqueId, and Parameters.
The following code sample uses the EnergyDataSettings class. The result appears in a TaskDialog after invoking the command.
**Code Region 28-7: Using the EnergyDataSettings class**
---
public void GetInfo_EnergyData(Document document)
{
EnergyDataSettings energyData = EnergyDataSettings.GetFromDocument(document);
if (null != energyData)
{
string message = "energyData : ";
message += "\nBuildingType : " + energyData.BuildingType;
TaskDialog.Show("Revit", message);
}
}
**Parent page:** [Analysis](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Analysis_html.html)

View File

@@ -0,0 +1,64 @@
# Path Of Travel
# Path Of Travel
The path of travel element allows you to analyze travel distances and times between 2 selected points in your model. The path of travel is generated based on the model elements acting as obstacles along the path of travel. It avoids contact with model elements in the analysis zone and calculates the shortest distance between the start and end points.
The class `Autodesk.Revit.DB.Analysis.PathOfTravel` represents this path element.
Members of this class include:
* PathOfTravel.Create() - creates a single PathOfTravel element given a start and end point.
* PathOfTravel.CreateMultiple() - creates multiple PathOfTravel elements given arrays of start and end points.
* PathOfTravel.CreateMapped() - creates multiple PathOfTravel elements by mapping each of a set of start points to each of a set of end points.
* PathOfTravel.GetCurves()
* PathOfTravel.LineStyle
* PathOfTravel.PathStart
* PathOfTravel.PathMidpoint
* PathOfTravel.PathEnd
* PathOfTravel.Update()
* PathOfTravel.UpdateMultiple()
The class `Autodesk.Revit.DB.Analysis.RouteAnalysisSettings` represents a settings element which contains project-wide settings for route calculations in plan views. Currently, these settings are only used by the Autodesk.Revit.DB.Analysis.PathOfTravel element, but in the future they can be used by any other functionalities which do route calculations.
Members of this class include:
* RouteAnalysisSettings.EnableIgnoredCategoryIds() - enable ignoring specified categories of elements during calculations
* RouteAnalysisSettings.SetIgnoredCategoryIds() - sets the categories to be ignored during calculations
* RouteAnalysisSettings.AnalysisZoneTopOffset - the analysis zone top (an offset above the level of the plan view)
* RouteAnalysisSettings.AnalysisZoneBottomOffset - the analysis zone bottom (an offset above the level of the plan view)
* RouteAnalysisSettings.IgnoreImports - If true, import instances are ignored by route calculation
## Reveal Obstacles mode for Path of Travel
The Reveal Obstacles view mode highlights elements in the plan view when those elements will act as obstacles for the current Path of Travel calculation settings. These methods provide access to read or set if a view is displaying this mode:
* PathOfTravel.IsInRevealObstaclesMode()
* PathOfTravel.SetRevealObstaclesMode()
## Path finding analysis for Path of Travel
`List<XYZ> PathOfTravel.FindStartsOfLongestPathsFromRooms(View view, List<XYZ> destinationPoints)` For a floor plan view, calculates paths from points inside rooms to the closests of the destinations. Returns the start points of the longest path(s). If multiple paths have the same longest length, returns multiple start points. The entire plan is divided in small tiles, and the distance to the closest destination point is calculated for each tile center point. Only tile center points that are located in rooms in the view are taken into account.
`List<XYZ> PathOfTravel.FindEndsOfShortestPaths(View view, List<XYZ> destinationPoints, List<XYZ> startPoints)` For a floor plan view, calculates the paths from each start point to its closest destination and return the path end points. The calculation is done in a floor plan with one or more destinationPoints and one or more startPoints. The shortest path is calculated from each start point to its corresponding closest destination.
`List<List<XYZ>> PathOfTravel.FindShortestPaths(View view, List<XYZ> destinationPoints, List<XYZ> startPoints)` For a floor plan view, calculates paths from each start point to its closest destinations. Returns the path, represented by an array of XYZ points. The calculation is done in a floor plan with one or more destinationPoints and one or more startPoints. The shortest path is calculated from each start point to its closest destination point.
## Waypoints
These methods provide access to read and modify the waypoints associated to a particular PathOfTravel element. Waypoints force the path of travel calculation to ensure that the path includes each of the specified points, in the order specified, between the start and end points.
* PathOfTravel.GetWaypoints()
* PathOfTravel.InsertWaypoint()
* PathOfTravel.SetWaypoint()
* PathOfTravel.RemoveWaypoint()
**Parent page:** [Analysis](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Analysis_html.html)

View File

@@ -0,0 +1,20 @@
# Analysis
# Analysis
#### Related Information
* [Green Building Studio API](http://www.autodesk.com/greenbuildingstudio-api-help-enu)
**Pages in this section**
* [Energy Data](Analysis/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Analysis_Energy_Data_html.html)
* [Analysis Visualization](Analysis/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Analysis_Analysis_Visualization_html.html)
* [Detailed Energy Analysis Model](Analysis/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Analysis_Detailed_Energy_Analysis_Model_html.html)
* [Path Of Travel](Analysis/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Analysis_Path_Of_Travel_html.html)
**Parent page:** [Advanced Topics](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_html.html)

View File

@@ -0,0 +1,30 @@
# Browser Organization
# Browser Organization
The BrowserOrganization class provides read-access to the settings for grouping, sorting, and filtering of items in the project browser.
BrowserOrganization.AreFiltersSatisfied() determines if the given element satisfies the filters defined by the browser organization.
## Getting the current organization
* GetCurrentBrowserOrganizationForViews() gets the BrowserOrganization that applies to the Views section of the project browser.
* GetCurrentBrowserOrganizationForSheets() gets the BrowserOrganization that applies to the Sheets section of the project browser.
* BrowserOrganization.GetCurrentBrowserOrganizationForSchedules() gets the BrowserOrganization that applies to the Schedules section of the project browser.
## Sorting
* SortingOrder The sorting order if sorting of items is applicable in the browser.
* SortingParameterId The id of the parameter used to determine the sorting order of items in the browser.
## FolderItemInfo
BrowserOrganization.GetFolderItems(ElementId) returns a collection of leaf FolderItemInfo objects each containing the given element Id.
FolderItemInfo contains the ElementId and Name info for each item in the organization settings of the project browser.
**Parent page:** [Advanced Topics](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_html.html)

View File

@@ -0,0 +1,138 @@
# Commands
# Commands
The Revit API provides access to existing Revit commands, either located on a tab, the application menu, or right-click menu. The main ways to work with Revit commands using the API is to either replace the existing command implementation or to post a command.
### Overriding a Revit command
The AddInCommandBinding class can be used to override an existing command in Revit. It has three events related to replacing the existing command implementation.
* **BeforeExecuted** \- This read-only event occurs before the associated command executes. An application can react to this event but cannot make changes to documents, or affect the invocation of the command.
* **CanExecute** \- Occurs when the associated command initiates a check to determine whether the command can be executed on the command target.
* **Executed** \- This event occurs when the associated command executes and is where any overriding implementation should be performed.
To create the commandbinding, call either UIApplication.CreateAddInCommandBinding() or UIControlledApplication.CreateAddInCommandBinding(). Both methods require a RevitCommandId id to identify the command handler you want to replace. The RevitCommandId has two static methods for obtaining a command's id:
* **LookupCommandId** \- Retrieves the Revit command id with the given id string. To find the command id string, open a session of Revit, invoke the desired command, close Revit, then look in the journal from that session. The "Jrn.Command" entry that was recorded when it was selected will have the string needed for LookupCommandId() and will look something like "ID_EDIT_DESIGNOPTIONS".
* **LookupPostableCommandId** \- Retrieves the Revit command id using the PostableCommand enumeration. This only works for commands which are postable (discussed in the following section).
The following example, taken from Revit 2014 SDK's DisableCommand sample, demonstrates how to create an AddInCommandBinding and override the implementation to disable the command with a message to the user.
**Code Region: Overriding a command**
---
/// <summary>
/// Implements the Revit add-in interface IExternalApplication
/// </summary>
public class MyApplication : IExternalApplication
{
#region IExternalApplication Members
/// <summary>
/// Implements the OnStartup event
/// </summary>
/// <param name="application"></param>
/// <returns></returns>
public Result OnStartup(UIControlledApplication application)
{
// Lookup the desired command by name
s_commandId = RevitCommandId.LookupCommandId(s_commandToDisable);
// Confirm that the command can be overridden
if (!s_commandId.CanHaveBinding)
{
ShowDialog("Error", "The target command " + s_commandToDisable +
" selected for disabling cannot be overridden");
return Result.Failed;
}
// Create a binding to override the command.
// Note that you could also implement .CanExecute to override the accessibiliy of the command.
// Doing so would allow the command to be grayed out permanently or selectively, however,
// no feedback would be available to the user about why the command is grayed out.
try
{
AddInCommandBinding commandBinding = application.CreateAddInCommandBinding(s_commandId);
commandBinding.Executed += DisableEvent;
}
// Most likely, this is because someone else has bound this command already.
catch (Exception)
{
ShowDialog("Error", "This add-in is unable to disable the target command " + s_commandToDisable +
"; most likely another add-in has overridden this command.");
}
return Result.Succeeded;
}
/// <summary>
/// Implements the OnShutdown event
/// </summary>
/// <param name="application"></param>
/// <returns></returns>
public Result OnShutdown(UIControlledApplication application)
{
// Remove the command binding on shutdown
if (s_commandId.HasBinding)
application.RemoveAddInCommandBinding(s_commandId);
return Result.Succeeded;
}
#endregion
/// <summary>
/// A command execution method which disables any command it is applied to (with a user-visible message).
/// </summary>
/// <param name="sender">Event sender.</param>
/// <param name="args">Arguments.</param>
private void DisableEvent(object sender, ExecutedEventArgs args)
{
ShowDialog("Disabled", "Use of this command has been disabled.");
}
/// <summary>
/// Show a task dialog with a message and title.
/// </summary>
/// <param name="title">The title.</param>
/// <param name="message">The message.</param>
private static void ShowDialog(string title, string message)
{
// Show the user a message.
TaskDialog td = new TaskDialog(title)
{
MainInstruction = message,
TitleAutoPrefix = false
};
td.Show();
}
/// <summary>
/// The string name of the command to disable. To lookup a command id string, open a session of Revit,
/// invoke the desired command, close Revit, then look to the journal from that session. The command
/// id string will be toward the end of the journal, look for the "Jrn.Command" entry that was recorded
/// when it was selected.
/// </summary>
static String s_commandToDisable = "ID_EDIT_DESIGNOPTIONS";
/// <summary>
/// The command id, stored statically to allow for removal of the command binding.
/// </summary>
static RevitCommandId s_commandId;
}
### Posting a command
The method UIApplication.PostCommand() will post a command to the Revit message queue to be invoked when control returns from the current API application. Only certain commands can be posted this way. They include all of the commands in the Autodesk.Revit.UI.PostableCommand enumerated type as well as external commands created by any add-in.
Note: Even a postable command may not execute when using PostCommand(). One reason this may happen is if another command has already been posted. Only one command may be posted to Revit at a given time, so if a second command is posted, PostCommand() will throw an exception. Another reason a posted command may not execute is if the command to be executed is not accessible at the time. Whether it is accessible is determined only at the point where Revit returns from the API context, so a failure to execute for this reason will not be reported directly back to the application that posted the command. UIApplication. CanPostCommand() can be used to identify if the given command can be posted, meaning whether it is a member of PostableCommand or an external command. It does not identify if the command is currently accessible.
Both PostCommand() and CanPostCommand() require a RevitCommandId which can be obtained as described in the "Overriding a Revit command" section above.
**Parent page:** [Advanced Topics](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_html.html)

View File

@@ -0,0 +1,96 @@
# Assemblies and Views
# Assemblies and Views
You can combine any number of model elements to create an assembly, which can then be edited, tagged, scheduled, and filtered.
## Creating assemblies
The static Create() method of the AssemblyInstance class is used to create a new assembly instance in the project. The Create() method must be created inside a transaction and the transaction must be committed before performing any action on the newly created assembly instance. The assembly type is assigned after the transaction is complete. Each unique assembly has its own AssemblyType.
The following example creates a new assembly instance, changes the name of its AssemblyType and then creates some views for the assembly instance.
**Code Region: Create Assembly and Views**
---
AssemblyInstance CreateAssemblyAndViews(Autodesk.Revit.DB.Document doc, ICollection<ElementId> elementIds)
{
AssemblyInstance assemblyInstance = null;
using (Transaction transaction = new Transaction(doc))
{
ElementId categoryId = doc.GetElement(elementIds.First()).Category.Id; // use category of one of the assembly elements
if (AssemblyInstance.IsValidNamingCategory(doc, categoryId, elementIds))
{
transaction.Start("Create Assembly Instance");
assemblyInstance = AssemblyInstance.Create(doc, elementIds, categoryId);
transaction.Commit(); // commit the transaction that creates the assembly instance before modifying the instance's name
if (transaction.GetStatus() == TransactionStatus.Committed)
{
transaction.Start("Set Assembly Name");
assemblyInstance.AssemblyTypeName = "My Assembly Name";
transaction.Commit();
}
if (assemblyInstance.AllowsAssemblyViewCreation()) // create assembly views for this assembly instance
{
if (transaction.GetStatus() == TransactionStatus.Committed)
{
transaction.Start("View Creation");
View3D view3d = AssemblyViewUtils.Create3DOrthographic(doc, assemblyInstance.Id);
ViewSchedule partList = AssemblyViewUtils.CreatePartList(doc, assemblyInstance.Id);
transaction.Commit();
}
}
}
}
return assemblyInstance;
}
Another way to create an AssemblyInstance is to use an existing AssemblyType. To create an AssemblyInstance using an AssemblyType, use the static method AssemblyInstance.PlaceInstance() and specify the ElementId of the AssemblyType to use and a location at which to place the assembly.
## Assembly Views
Various assembly views can be created for an assembly instance using static methods of the AssemblyViewUtils class, including an orthographic 3D assembly view, a detail section assembly view, a material takeoff multicategory schedule assembly view, a part list multicategory schedule assembly view, a single-category schedule and a sheet assembly view. All of these except sheet views have overloaded creation methods which create the schedule or view from a template. In addition to a template Id, these overloads have a parameter to indicate if the template will be assigned or applied.
Note that assembly views must all be assigned to the same assembly instance of the assembly type. AssemblyInstance.AllowsAssemblyViewCreation() returns true if that assembly instance can accept new assembly views (either because it already has views or because no assembly instance has views).
The following example creates a new single-category schedule for an assembly from a given template.
**Code Region: Create assembly view from template**
---
private ViewSchedule CreateScheduleForAssembly(Document doc, AssemblyInstance assemblyInstance, ElementId viewTemplateId)
{
ViewSchedule schedule = null;
if (assemblyInstance.AllowsAssemblyViewCreation()) // create assembly views for this assembly instance
{
using (Transaction transaction = new Transaction(doc))
{
transaction.Start("Create Schedule");
// use naming category for the schedule
if (ViewSchedule.IsValidCategoryForSchedule(assemblyInstance.NamingCategoryId))
{
schedule = AssemblyViewUtils.CreateSingleCategorySchedule(doc, assemblyInstance.Id, assemblyInstance.NamingCategoryId, viewTemplateId, false);
}
transaction.Commit();
if (schedule != null && transaction.GetStatus() == TransactionStatus.Committed)
{
transaction.Start("Edit Schedule");
schedule.Name = "AssemblyViewSchedule";
transaction.Commit();
}
}
}
return schedule;
}
The document must be regenerated before using any of these newly created assembly views. You'll note in the example above that a transaction is committed after creating a new assembly view. The Commit() method automatically regenerates the document.
**Parent page:** [Construction Modeling](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Construction_Modeling_html.html)

View File

@@ -0,0 +1,77 @@
# Parts
# Parts
Parts can be generated from elements with layered structures, such as:
* Walls (excluding stacked walls and curtain walls)
* Floors (excluding shape-edited floors)
* Roofs (excluding those with ridge lines)
* Ceilings
* Structural slab foundations
In the Revit API, elements can be divided into parts using the PartUtils class. The static method PartUtils.CreateParts() is used to create parts from one or more elements. Note that this method instantiates a PartMaker and creates Parts that will be split in smaller parts if you chose to use DivideParts. The PartMaker uses its embedded rules to drive creation of the needed parts during regeneration.
The API also offers an interface to subdivide parts. PartUtils.DivideParts() accepts as input a collection of part ids, a collection of “intersecting element” ids (which can be layers and grids), and a collection of curves. The routine uses the intersecting elements and curves as boundaries from which to divide and generate new parts.
The GetAssociatedParts() method can be called to find some or all of the parts associated with an element, or use HasAssociatedParts() to determine if an element has parts.
You can delete parts through the API either by deleting the individual part elements, or by deleting the PartMaker associated to the parts (which will delete all parts generated by this PartMaker after the next regeneration).
Parts can be manipulated in the Revit API much the same as they can in the Revit user interface. For example, the outer boundaries of parts may be offset with PartUtils.SetFaceOffset().
* * *
The following example offsets all the faces of a part that can be offset.
**Code Region: Offset Faces of a Part**
---
public void OffsetPartFaces(Part part)
{
Document doc = part.Document;
Autodesk.Revit.DB.GeometryElement geomElem = part.get_Geometry(new Options());
foreach(GeometryObject geomObject in geomElem)
{
if (geomObject is Solid)
{
Solid solid = geomObject as Solid;
FaceArray faceArray = solid.Faces;
foreach (Face face in faceArray)
{
if (part.CanOffsetFace(face))
{
part.SetFaceOffset(face, 1);
}
}
}
}
}
**Before and After Offseting faces of a selected Part**
## Returning the entities that create a divided Part
These methods identify and return the curves that were sketched to create the part division and, optionally, also outputs also the sketch plane for those curves.
* PartUtils.GetSplittingCurves(Document, ElementId)
* PartUtils.GetSplittingCurves(Document, ElementId, out SketchPlane)
`PartUtils.GetSplittingElements(Document, ElementId)`identifies and returns the elements ( ReferencePlane, Level or Grid ) that were used to create the division.
## Parts and Direct Shapes
Parts can be created from DirectShape instances, either in the same host document or in a link. These methods indicate whether it is possible to create parts from an instance of one of those classes.
* DirectShape.CanCreateParts()
* DirectShapeType.CanCreateParts()
**Parent page:** [Construction Modeling](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Construction_Modeling_html.html)

View File

@@ -0,0 +1,23 @@
# Construction Modeling
# Construction Modeling
The Revit API allows elements to be divided into sub-parts or collected into assemblies to support construction modeling workflows, much the same way as can be done with the Revit user interface. Both parts and assemblies can be independently scheduled, tagged, filtered, and exported. You can also divide a part into smaller parts. After creating an assembly type, you can place additional instances in the project and generate isolated assembly views.
The main classes related to Construction Modeling are:
* **AssemblyInstance** \- This class combines multiple elements for tagging, filtering, scheduling and creating isolated assembly views.
* **AssemblyType** \- Represents a type for construction assembly elements. Each new unique assembly created in the project automatically creats a corresponding AssemblyType. A new AssemblyInstance can be placed in the document from an existing AssemblyType.
* **PartUtils** \- This utility class contains general part utility methods, including the ability to create parts, divide parts, and to get information about parts.
* **AssemblyViewUtils** \- A utility class to create various types of assembly views.
**Pages in this section**
* [Assemblies and Views](Construction_Modeling/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Construction_Modeling_Assemblies_and_Views_html.html)
* [Parts](Construction_Modeling/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Construction_Modeling_Parts_html.html)
**Parent page:** [Advanced Topics](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_html.html)

View File

@@ -0,0 +1,26 @@
# Context Menus
# Context Menus
Context menus can be created from an add-in using the interface:
The constructors are:
* `Revit.UI.ContextMenu()` \- Creates a new instance of Context Menu.
* `Revit.UI.CommandMenuItem(name , className, assemblyName )` \- Creates a new instance of command menu item with name, external command class name and external application assembly name.
* `Revit.UI.SubMenuItem(name , ContextMenu)` \- Creates a new instance of flyout menu with name and sub menu instance.
* `Revit.UI.Separator()` \- Creates a new instance of separator menu item.
The methods are
* `ContextMenu.AddItem()` \- Adds a specific type of MenuItem object to context menu.
* `CommandMenuItem.SetAvailabilityClassName()` \- Sets the availabilityClassName of CommandMenuItem.
* `CommandMenuItem.SetToolTip()` \- Sets the tooltip of a CommandMenuItem.
* `IContextMenuCreator.BuildContextMenu()` \- Adds menu items to the passed in ContextMenu object.
* `UIControlledApplication.RegisterContextMenu()` \- Registers a new context menu.
**Parent page:** [Advanced Topics](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_html.html)

View File

@@ -0,0 +1,23 @@
# Dockable Dialog Panes
# Dockable Dialog Panes
Since Revit 2013, applications have been able to use modeless dialogs by taking advantage of the [User Interface Event](./Events/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Events_User_Inteface_Events_html.html) and the [External Events](./Revit_API_Revit_API_Developers_Guide_Advanced_Topics_External_Events_html.html) class in the Revit API. Add-ins requiring modeless dialogs also have the option to use dockable modeless dialogs. Similar to standard modeless dialogs, dockable dialogs are registered Windows Presentation Foundation (WPF) dialog panes that participate in Revit's window docking system. A registered dockable pane can dock into the top, left, right, and bottom of the main Revit window, as well as be added as a tab to an existing system pane, such as the project browser. Additionally, dockable panes can float, behaving much like a standard modeless dialog.
### IDockablePaneProvider
Registering a dockable pane requires an instance of the IDockablePaneProvider interface. The SetupDockablePane() method of this interface is called during initialization of the Revit user interface to gather information about add-in dockable pane windows. SetupDockablePane() has one parameter of type DockablePaneProviderData, which is a container for information about the new dockable pane.
Implementations of the IDockablePaneProvider interface should set the FrameworkElement and InitialState properties of DockablePaneProviderData. The FrameworkElement property is the Windows Presentation Framework object containing the pane's user interface.
Note: It is recommended that the dockable dialog in the add-in be the class that implements IDockablePaneProvider and that it be subclassed from System.Windows.Controls.Page.
The InitialState property is the initial position and settings of the docking pane, indicated by the DockablePaneState class. The pane's DockPosition can be Top, Bottom, Left, Right, Floating or Tabbed. If the position is Tabbed, the DockablePaneState.TabBehind property can be used to specify which pane the new pane will appear behind. If the position is Floating, the DockablePaneState.FloatingRectangle property contains the rectangle that determines the size and position of the pane.
### DockablePane
To access a dockable pane during runtime, it needs to be registered by calling the UIApplication.RegisterDockablePane() method. This method requires a unique identifier for the new pane (DockablePaneId), a string specifying the caption for the pane, and an implementation of the IDockablePaneProvider interface.
Dockable panes can be accessed by calling UIApplication.GetDockablePane() and passing in the unique DockablePaneId.This method returns a DockablePane. DockablePane.Show() will display the pane in the Revit user interface at its last docked location, if not currently visible. DockablePane.Hide() will hide a visible dockable pane. However, it has no effect on built-in Revit dockable panes.
**Parent page:** [Advanced Topics](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_html.html)

View File

@@ -0,0 +1,33 @@
# Exposure to End-User
# Exposure to End-User
When updaters work as they should, they are transparent to the user. In some special cases though, Revit will display a warning to the user concerning a 3rd party updater. Such messages will use the value of the GetUpdaterName() method to refer to the updater.
### Updater not installed
If a document is modified by a non-optional updater and later loaded when that updater is not installed, a task dialog similar to the following is displayed:
**Figure 135: Missing Third Party Updater Warning**
### Updater performs invalid operation
If an updater has an error, such as an unhandled exception, a message similar to the following is displayed giving the user the option to disable the updater:
**Figure 136: Updater performed an invalid operation**
If the user selects Cancel, the entire transaction is rolled back. In the Wall Updater example from earlier in this chapter, the newly added wall is removed. If the user selects Disable Updater, the updater is no longer called, but the transaction is not rolled back.
### Infinite loop
In the event that an updater falls into an infinite loop, Revit will notify the user and disable the updater for the duration of the Revit session.
### Two updaters attempt to edit same element
If an updater attempts to edit the same parameter of an element that was updated by another updater in the same transaction, or if an updater attempts to edit the geometry of an element in a way that conflicts with a change made by another updater, the updater is canceled, an error message is displayed and the user is given the option to disable the updater.
### Central document modified by updater not present locally
If the user reloads latest or saves to central with a central file that was modified by an updater that is not installed locally, a task dialog is presented giving them the option to continue or cancel the synchronization. The warning indicates that proceeding may cause problems with the central model when it is used with the third party updater at a later time.
**Parent page:** [Dynamic Model Update](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Dynamic_Model_Update_html.html)

View File

@@ -0,0 +1,119 @@
# Implementing IUpdater
# Implementing IUpdater
The IUpdater interface requires that the following 5 methods to be implemented:
* GetUpdaterId() - This method should return a globally unique Id for the Updater consisting of the application Id plus a GUID for this Updater. This method is called once during registration of the Updater.
* GetUpdaterName() - This returns a name by which the Updater can be identified to the user, if there is a problem with the Updater at runtime.
* GetAdditionalInformation() - This method should return auxiliary text that Revit will use to inform the end user when the Updater is not loaded.
* GetChangePriority() - This method identifies the nature of the changes the Updater will be performing. It is used to identify the order of execution of updaters. This method is called once during registration of the Updater.
* Execute() - This is the method that Revit will invoke to perform an update. See the next section for more information on the Execute() method.
If a document is modified by an Updater, the document will store the unique Id of the updater. If the user later opens the document and the Updater is not present, Revit will warn the user that the 3rd party updater which previously edited the document is not available unless the Updater is flagged as optional. By default, updaters are non-optional and optional updaters should be used only when necessary.
The following code is a simple example of implementing the IUpdater interface (to change the WallType for newly added walls) and registering the updater in the OnStartup() method. It demonstrates all the key aspects of creating and using an updater.
**Code Region 25-1: Example of implementing IUpdater**
---
public class WallUpdaterApplication : Autodesk.Revit.UI.IExternalApplication
{
public Result OnStartup(Autodesk.Revit.UI.UIControlledApplication application)
{
// Register wall updater with Revit
WallUpdater updater = new WallUpdater(application.ActiveAddInId);
UpdaterRegistry.RegisterUpdater(updater);
// Change Scope = any Wall element
ElementClassFilter wallFilter = new ElementClassFilter(typeof(Wall));
// Change type = element addition
UpdaterRegistry.AddTrigger(updater.GetUpdaterId(), wallFilter, Element.GetChangeTypeElementAddition());
return Result.Succeeded;
}
public Result OnShutdown(Autodesk.Revit.UI.UIControlledApplication application)
{
WallUpdater updater = new WallUpdater(application.ActiveAddInId);
UpdaterRegistry.UnregisterUpdater(updater.GetUpdaterId());
return Result.Succeeded;
}
}
public class WallUpdater : IUpdater
{
static AddInId m_appId;
static UpdaterId m_updaterId;
WallType m_wallType = null;
// constructor takes the AddInId for the add-in associated with this updater
public WallUpdater(AddInId id)
{
m_appId = id;
m_updaterId = new UpdaterId(m_appId, new Guid("FBFBF6B2-4C06-42d4-97C1-D1B4EB593EFF"));
}
public void Execute(UpdaterData data)
{
Document doc = data.GetDocument();
// Cache the wall type
if (m_wallType == null)
{
FilteredElementCollector collector = new FilteredElementCollector(doc);
collector.OfClass(typeof(WallType));
var wallTypes = from element in collector
where
element.Name == "Exterior - Brick on CMU"
select element;
if (wallTypes.Count<Element>() > 0)
{
m_wallType = wallTypes.Cast<WallType>().ElementAt<WallType>(0);
}
}
if (m_wallType != null)
{
// Change the wall to the cached wall type.
foreach (ElementId addedElemId in data.GetAddedElementIds())
{
Wall wall = doc.GetElement(addedElemId) as Wall;
if (wall != null)
{
wall.WallType = m_wallType;
}
}
}
}
public string GetAdditionalInformation()
{
return "Wall type updater example: updates all newly created walls to a special wall";
}
public ChangePriority GetChangePriority()
{
return ChangePriority.FloorsRoofsStructuralWalls;
}
public UpdaterId GetUpdaterId()
{
return m_updaterId;
}
public string GetUpdaterName()
{
return "Wall Type Updater";
}
}
**Parent page:** [Dynamic Model Update](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Dynamic_Model_Update_html.html)

View File

@@ -0,0 +1,38 @@
# Registering Updaters
# Registering Updaters
Updaters must be registered in order to be notified of changes to the model. The application level UpdaterRegistry class provides the ability to register/unregister and manipulate the options set for Updaters. Updaters may be registered from any API callback and can be registered as application-wide or document-specific, meaning they will only be triggered by changes made to the specified document. In order to use the UpdaterRegistry functionality, the Revit add-in must be registered in a manifest file and the Id returned by UpdaterId.GetAddInId() for any Updater (obtained from GetUpdaterId()) must match the AddInId field in the add-in's manifest file. An add-in cannot add, remove, or modify Updaters that do not belong to it.
### Triggers
In addition to calling the UpdaterRegistry.RegisterUpdater() method, Updaters should add one or more update triggers via the AddTrigger() methods. These triggers indicate to the UpdaterRegistry what events should trigger the Updaters Execute() method to run. They can be set application-wide, or can apply to changes made in a specific document. Update triggers are specified by pairing a change scope and a change type.
The change scope is one of two things:
* An explicit list of element Ids in a document - only changes happening to those elements will trigger the Updater
* An implicit list of elements communicated via an ElementFilter - every changed element will be run against the filter, and if any pass, the Updater is triggered
There are several options available for change type. ChangeTypes are obtained from static methods on the Element class.
* Element addition - via Element.GetChangeTypeElementAddition()
* Element deletion - via Element.GetChangeTypeElementDeletion()
* Change of element geometry (shape or position) - via Element.GetChangeTypeGeometry()
* Changing value of a specific parameter - via Element.GetChangeTypeParameter()
* Any change of element - via Element.GetChangeTypeAny().
Note that geometry changes are triggered due to potentially many causes, like a change of element type, modification of properties and parameters, move and rotate, or changes imposed on the element from other modified elements during regeneration.
Also note that the last option, any change of element, only triggers the Updater for modifications of pre-existing elements, and does not trigger the Updater for newly added or deleted elements. Additionally, when using this trigger for an instance, only certain modifications to its type will trigger the Updater. Changes that affect the instance itself, such as modification of the instance's geometry, will trigger the Updater. However, changes that do not modify the instance directly and do not result in any discernable change to the instance, such as changes to text parameters, will not trigger the Updater for the instance. To trigger based on these changes, the Type must also be included in the trigger's change scope.
### Order of Execution
The primary way that Revit sorts multiple Updaters to execute in the correct order is by looking at the ChangePriority returned by a given Updater. An Updater reporting a priority for a more fundamental set of elements (e.g., GridsLevelsReferencePlanes) will execute prior to Updaters reporting a priority for elements driven by these fundamental elements (e.g., Annotations). Reporting a proper change priority for the elements which your Updater modifies benefits users of your application: Revit is less likely to have to execute the Updater a second time due to changes made by another Updater.
For Updaters which report the same change priority, execution is ordered based on a sorting of UpdaterId. The method UpdaterRegistry.SetExecutionOrder() allows you set the execution order between any two registered Updaters (even updaters registered by other API add-ins) so long as your code knows the ids of the two Updaters.
**Parent page:** [Dynamic Model Update](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Dynamic_Model_Update_html.html)

View File

@@ -0,0 +1,51 @@
# The Execute Method
# The Execute Method
The purpose of the Execute() method is to allow your Updater to react to changes that have been made to the document, and make appropriate related. This method is invoked by Revit at the end of a document transaction in which elements that matched the UpdateTrigger for this Updater were added, changed or deleted. The method may be invoked more than once for the same transaction due to changes made by other Updaters. Updaters are invoked before the DocumentChanged event, so this event will contain changes made by all updaters.
All changes to the document made during the invocation of this method will become a part of the invoking transaction, and maintained for undo and redo operations. When implementing this method you may not open any new transactions (an exception will be thrown), but you may use sub-transactions as required.
Although it can be used to also update data outside of the document, such changes will not become part of the original transaction and will not be subject to undo or redo when the original transaction is undone or redone. If you do use this method to modify data outside of the document, you should also subscribe to the DocumentChanged event to update your data when the original transaction is undone or redone.
### Scope of Changes
The Execute() method has an UpdaterData parameter that provides all necessary data needed to perform the update, including the document and information about the changes that triggered the update. Three basic methods (GetAddedElementIds(),GetDeletedElementIds(), and GetModifiedElementIds()) identify the elements that triggered the update. The Updater can also check specifically if a particular change triggered the update by using the IsChangeTriggered() method.
### Forbidden and Cautionary Changes
The following methods may not be called while executing an Updater, because they introduce cross references between elements. (This can result in document corruption when these changes are combined with workset operations.) A ForbiddenForDynamicUpdateException will be thrown when an updater attempts to call any of these methods:
* Autodesk.Revit.DB.ViewSheet.AddView()
* Autodesk.Revit.DB.Document.LoadFamily(Autodesk.Revit.DB.Document, Autodesk.Revit.DB.IFamilyLoadOptions)
* AreaReinforcement.Create()
* PathReinforcement.Create()
In addition to the forbidden methods listed above, other API methods that require documents to be in transaction-free state may not be called either. Such methods include but are not limited to Save(), SaveAs(), Close(), LoadFamily(), etc. Please refer to the documentation of the respective methods for more information.
Calls to the UpdaterRegistry class, such as RegistryUpdater() or AddTrigger(), from within the Execute() method of an updater are also forbidden. Calling any of the UpdaterRegistry methods will throw an exception. The one exception to this rule is the UpdaterRegistry.UnregisterUpdater() method, which may be called during execution of an updater as long as the updater to be unregistered is not the one currently being executed.
Although the following methods are allowed during execution of an Updater, they can also throw ForbiddenForDynamicUpdateException when cross-references between elements are established as a result of the call. One such example could be creating a face wall that intersects with an existing face wall, so those two would have to be joined together. Apply caution when calling these methods from an Updater:
* Autodesk.Revit.Creation.ItemFactoryBase.NewFamilyInstances2()
* Autodesk.Revit.Creation.ItemFactoryBase.NewFamilyInstance(Autodesk.Revit.DB.XYZ, Autodesk.Revit.DB.FamilySymbol, Autodesk.Revit.DB.Element,Autodesk.Revit.DB.Structure.StructuralType)
* Autodesk.Revit.Creation.Document.NewFamilyInstance(Autodesk.Revit.DB.XYZ, Autodesk.Revit.DB.FamilySymbol, Autodesk.Revit.DB.Element, Autodesk.Revit.DB.Level, Autodesk.Revit.DB.Structure.StructuralType)
* Autodesk.Revit.DB.FaceWall.Create()
It should also be noted that deleting and recreating existing elements should be avoided if modifying them would suffice. While deleting elements may be a simpler solution, it will not only affect Revit's performance, but it will also destroy any references to "recreated" objects from other elements. This could cause the user to lose work they have done to constrain and annotate the elements in question.
### Managing Changes
Updaters need to be able to handle complex issues that may arise from their use, possibly reconciling subsequent changes to an element. Elements modified by an updater may change by the time the updater is next invoked, and those changes may impact information modified by the updater. For example, the element may be explicitly edited by the user, or implicitly edited due to propagated changes triggered by a regeneration.
It is also possible that the same element may be modified by another updater, possibly even within the same transaction. Although explicit changes of exactly the same data is tracked and prohibited, indirect or propagated changes are still possible. Perhaps the most complex case is that an element could be changed by the user and/or the same updater in different versions of the file. After the user reloads the latest or saves to central, the modified target element will be brought from the other file and the updater will need to reconcile changes.
It is also important to realize that when a document synchs with the central file, the ElementId of elements may be affected. If new elements have been added to two versions of the same file and the same ElementId is used in both places, this will be reconciled when the files are synched to the central database. For this reason, when using updaters to cross-reference one element in another element, they should use Element.UniqueId which is guaranteed to be unique.
Another issue to consider is if an updater attaches some data (i.e. as a parameter) to an element, it not only must be sure to maintain that information in the element to which it was added, but also to reconcile data in cases when that element is duplicated via copy/paste or group propagation. For example, if an updater adds a parameter "Total weight of rebar" to a rebar host, that parameter and its value will be copied to the duplicated rebar host even though the rebar itself may be not copied with the host. In this case the updater needs to ensure the parameter value is reset in the newly copied rebar host.
**Parent page:** [Dynamic Model Update](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Dynamic_Model_Update_html.html)

View File

@@ -0,0 +1,16 @@
# Dynamic Model Update
# Dynamic Model Update
Dynamic model update offers the ability for a Revit API application to modify the Revit model as a reaction to changes happening in the model when those changes are about to be committed at the end of a transaction. Revit API applications can create updaters by implementing the IUpdater interface and registering it with the UpdaterRegistry class. Registering includes specifying what changes in the model should trigger the updater.
**Pages in this section**
* [Implementing IUpdater](Dynamic_Model_Update/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Dynamic_Model_Update_Implementing_IUpdater_html.html)
* [The Execute Method](Dynamic_Model_Update/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Dynamic_Model_Update_The_Execute_method_html.html)
* [Registering Updaters](Dynamic_Model_Update/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Dynamic_Model_Update_Registering_Updaters_html.html)
* [Exposure to End-User](Dynamic_Model_Update/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Dynamic_Model_Update_Exposure_to_End_User_html.html)
**Parent page:** [Advanced Topics](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_html.html)

View File

@@ -0,0 +1,31 @@
# Canceling Events
# Canceling Events
Events that are triggered before an action has taken place (i.e. DocumentSaving) are often cancellable. (Use the Cancellable property to determine if the event can be cancelled.) For example, you may want to check some criteria are met in a model before it is saved. By registering for the DocumentSaving or DocumentSavingAs event, for example, you can check for certain criteria in the document and cancel the Save or Save As action. Once cancelled, an event cannot be un-cancelled.
Note: If a pre-event is cancelled, other event handlers that have subscribed to the event will not be notified. However, handlers that have subscribed to a post-event related to the pre-event will be notified. The following event handler for the DocumentSavingAs event checks if the ProjectInformation Status parameter is empty, and if it is, cancels the SaveAs event. Note that if your application cancels an event, it should offer an explanation to the user. **Code Region 24-2: Canceling an Event**
---
private void CheckProjectStatusInitial(Object sender, DocumentSavingAsEventArgs args)
{
Document doc = args.Document;
ProjectInfo proInfo = doc.ProjectInformation;
// Project information is only available for project document.
if (null != proInfo)
{
if (string.IsNullOrEmpty(proInfo.Status))
{
// cancel the save as process.
args.Cancel();
TaskDialog.Show("Error", "Status project parameter is not set. Save is aborted.");
}
}
}
Note: Although most event arguments have the Cancel and Cancellable properties, the DocumentChanged and FailuresProcessing events have corresponding Cancel() and IsCancellable() methods.
**Parent page:** [Events](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Events_html.html)

View File

@@ -0,0 +1,9 @@
# DocumentChanged event
# DocumentChanged event
The DocumentChanged event is triggered when the Revit document has changed. This event is raised whenever a Revit transaction is either committed, undone or redone. This is a read-only event, designed to allow external data to be kept in synch with the state of the Revit database. To update the Revit database in response to changes in elements, use the IUpdater framework.
The DocumentChangedEventArgs class is used by the DocumentChanged event. This class has several methods to get the element Ids of any newly added elements (GetAddElementIds()), deleted elements (GetDeletedElementIds()) or elements that have been modified (GetModifiedElementIds()). The GetAddElementIds() and GetModifiedElementIds() methods have overloads that take an ElementFilter, which makes it easy to detect only changes of interest.
**Parent page:** [Database Events](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Events_Database_Events_html.html)

View File

@@ -0,0 +1,67 @@
# Database Events
# Database Events
The following table lists database events, their type and whether they are available at the application and/or document level:
**Table 53: DB Event Types**
**Event** | **Type** | **Application** | **Document**
---|---|---|---
[DocumentChanged event](./Database_Events/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Events_Database_Events_DocumentChanged_event_html.html) | single | X |
DocumentClosing | pre | X | X
DocumentClosed | post | X |
DocumentCreating | pre | X |
DocumentCreated | post | X |
DocumentOpening | pre | X |
DocumentOpened | post | X |
DocumentPrinting | pre | X | X
DocumentPrinted | post | X | X
DocumentSaving | pre | X | X
DocumentSaved | post | X | X
DocumentSavingAs | pre | X | X
DocumentSavedAs | post | X | X
DocumentSynchronizingWithCentral | pre | X |
DocumentSynchronizedWithCentral | post | X |
FailuresProcessing | single | X |
FileExporting | pre | X |
FileExported | post | X |
FileImporting | pre | X |
FileImported | post | X |
ProgressChanged | single | X |
ViewPrinting | pre | X | X
ViewPrinted | post | X | X
* DocumentChanged - notification when a transaction is committed, undone or redone
* DocumentClosing - notification when Revit is about to close a document
* DocumentClosed - notification just after Revit has closed a document
* DocumentCreating - notification when Revit is about to create a new document
* DocumentCreated - notification when Revit has finished creating a new document
* DocumentOpening - notification when Revit is about to open a document
* DocumentOpened - notification after Revit has opened a document
* DocumentPrinting - notification when Revit is about to print a view or ViewSet of the document
* DocumentPrinted - notification just after Revit has printed a view or ViewSet of the document
* DocumentSaving - notification when Revit is about to save the document
* DocumentSaved - notification just after Revit has saved the document
* DocumentSavingAs - notification when Revit is about to save the document with a new name
* DocumentSavedAs - notification when Revit has just saved the document with a new name
* DocumentSynchronizingWithCentral - notification when Revit is about to synchronize a document with the central file
* DocumentSynchronizedWithCentral - notification just after Revit has synchronized a document with the central file
* FailuresProcessing - notification when Revit is processing failures at the end of a transaction
* FileExporting - notification when Revit is about to export to a file format supported by the API
* FileExported - notification after Revit has exported to a file format supported by the API
* FileImporting - notification when Revit is about to import a file format supported by the API
* FileImported - notification after Revit has imported a file format supported by the API
* ProgressChanged - notification when an operation in Revit has progress bar data
* ViewPrinting - notification when Revit is about to print a view of the document
* ViewPrinted - notification just after Revit has printed a view of the document
**Pages in this section**
* [DocumentChanged event](Database_Events/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Events_Database_Events_DocumentChanged_event_html.html)
**Parent page:** [Events](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Events_html.html)

View File

@@ -0,0 +1,70 @@
# Registering Events
# Registering Events
Learn where and how to register events.
Using events is a two step process. First, you must have a function that will handle the event notification. This function must take two parameters, the first is an Object that denotes the "sender" of the event notification, the second is an event-specific object that contains event arguments specific to that event. For example, to register the DocumentSavingAs event, your event handler must take a second parameter that is a DocumentSavingAsEventArgs object.
The second part of using an event is registering the event with Revit. This can be done as early as in the OnStartup() function through the ControlledApplication parameter, or at any time after Revit starts up. Although events can be registered for External Commands as well as External Applications, it is not recommended unless the External Command registers and unregisters the event in the same external command. Also note that registering to and unregistering from events must happen while executing on the main thread. An exception will be thrown if an external application attempts to register to (or unregister from) events from outside of a valid API context.
The following example registers the DocumentOpened event, and when that event is triggered, this application will set the address of the project.
**Code Region 24-1: Registering ControlledApplication.DocumentOpened**
---
public class Application_DocumentOpened : IExternalApplication
{
/// <ExampleMethod>
/// <summary>
/// Implement this method to subscribe to event.
/// </summary>
public Result OnStartup(UIControlledApplication application)
{
try
{
// Register event.
application.ControlledApplication.DocumentOpened += new EventHandler
<Autodesk.Revit.DB.Events.DocumentOpenedEventArgs>(application_DocumentOpened);
}
catch (Exception)
{
return Result.Failed;
}
return Result.Succeeded;
}
public Result OnShutdown(UIControlledApplication application)
{
// remove the event.
application.ControlledApplication.DocumentOpened -= application_DocumentOpened;
return Result.Succeeded;
}
public void application_DocumentOpened(object sender, DocumentOpenedEventArgs args)
{
// get document from event args.
Document doc = args.Document;
// Following code snippet demonstrates support of DocumentOpened event to modify the model.
// Because DocumentOpened supports model changes, it allows user to update document data.
// Here, this sample assigns a specified value to ProjectInformation.Address property.
// User can change other properties of document or create(delete) something as he likes.
//
// Please note that ProjectInformation property is empty for family document.
// So please don't run this sample on family document.
using (Transaction transaction = new Transaction(doc, "Edit Address"))
{
if (transaction.Start() == TransactionStatus.Started)
{
doc.ProjectInformation.Address =
"United States - Massachusetts - Waltham - 1560 Trapelo Road";
transaction.Commit();
}
}
}
}
**Parent page:** [Events](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Events_html.html)

View File

@@ -0,0 +1,29 @@
# User Inteface Events
# User Inteface Events
The following table lists user interface events, their type and whether they are available at the application and/or document level:
**Table 54: UI Event Types**
**Event** | **Type** | **UIApplication** | **ControlledApplication** | **UIDocument**
---|---|---|---|---
ApplicationClosing | pre | X | |
ApplicationInitialized | single | | X |
DialogBoxShowing | single | X | |
DisplayingOptionsDialog | single | X | |
Idling | single | X | |
ViewActivating | pre | X | |
ViewActivated | post | X | |
* ApplicationClosing - notification when the Revit application is about to be closed
* ApplicationInitialized - notification after the Revit application has been initialized, after all external applications have been started and the application is ready to work with documents
* DialogBoxShowing - notification when Revit is showing a dialog or message box
* DisplayingOptionsDialog - notification when Revit options dialog is displaying
* Idling - notification when Revit is not in an active tool or transaction
* ViewActivating - notification when Revit is about to activate a view of the document
* ViewActivated - notification just after Revit has activated a view of the document
**Parent page:** [Events](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Events_html.html)

View File

@@ -0,0 +1,22 @@
# Events
# Events
Events are notifications that are triggered on specific actions in the Revit user interface or API workflows. By subscribing to events, an add-in application can be notified when an action is about to happen or has just happened and take some action related to that event. Some events come in pairs around actions, one occurring before the action takes place ("pre" event) and the other happening after the action takes place ("post" event). Events that do not occur in these pre/post pairs are called "single" events.
Revit provides access to events at both the Application level (such as ApplicationClosing or DocumentOpened) and the Document level (such as DocumentClosing and DocumentPrinting). The same application level events available from the Application class are also available from the ControlledApplication class, which represents the Revit application with no access to documents. It is ControlledApplication that is available to add-ins from the OnStartup() and OnShutdown() methods. In terms of subscribing and unsubscribing to events, these classes are interchangeable; subscribing to an event from the ControlledApplication class is the same as subscribing from the Application class.
Events can also be categorized as database (DB) events or user interface (UI) events. DB events are available from the Application and Document classes, while UI events are available from the UIApplication class. (Currently all UI events are at the application level only).
Some events are considered read-only, which means that during their execution the model may not be modified. The fact that an event is read-only is documented in the API help file. It is important to know that even during regular events (i.e. not read-only events), the model may be in a state in which it cannot be modified. The programmer should check the properties Document.IsModifiable and Document.IsReadOnly to determine whether the model may be modified.
**Pages in this section**
* [Database Events](Events/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Events_Database_Events_html.html)
* [User Inteface Events](Events/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Events_User_Inteface_Events_html.html)
* [Registering Events](Events/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Events_Registering_Events_html.html)
* [Canceling Events](Events/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Events_Canceling_Events_html.html)
**Parent page:** [Advanced Topics](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_html.html)

View File

@@ -0,0 +1,88 @@
# Custom Export
# Custom Export
Use a custom export process to export views from a Revit document.
The Revit API provides a set of classes that make it possible to export views via a custom export context. These classes provide access to the rendering output pipeline through which Revit sends the graphical representation of a model to an output device. In the case of a custom export, the "device" is represented by a context object that could be any kind of a device. A file would be the most common case.
An implementation of a custom exporter provides a context and invokes rendering of a model, upon which Revit starts processing the model and sends graphic data out via methods of the context. The data describes the model exactly as it would have appeared in Revit when the model is rendered. The data includes all geometry and material properties.
## CustomExporter class
The CustomExporter class allows exporting views via a custom export context. The Export() method of this class triggers the standard rendering process in Revit, but instead of displaying the result on screen or printer, the output is channeled through the given custom context that handles processing the geometric as well as non-geometric information.
### CustomExporter support for 2D views
CustomExporter can export 2D plan, section and elevation views.
The method `CustomExporter.Export(IList<ElementId>)` can accept either 3D or 2D views, with the limitation that views in the collection must be either all 3D or all 2D.
For both Export() calls, the exporter context must correspond to the views' type; use IModelExportContext or IPhotoRenderContext for 3D views and IExportContext2D for 2D views.
Several properties for the CustomExporter exist to support 2D objects:
* CustomExporter.Export2DGeometricObjectsIncludingPatternLines - Indicates whether pattern lines of geometric objects should be exported in a 2D context. Defaults to false.
* CustomExporter.Export2DIncludingAnnotationObjects - Indicates whether annotation objects should be exported in a 2D context. Defaults to false.
* CustomExporter.Export2DForceDisplayStyle - Forces a display style for the export. If the style is DisplayStyle.Undefined, then export uses DisplayStyle.Wireframe for wireframe views and DisplayStyle.HLR for other views. Defaults to DisplayStyle.Undefined.
Use the interface `IExportContext2D` for exporting 2D views. It has the following methods in addition to the method inherited from IExportContext:
* IExportContext2D.OnElementBegin2D()
* IExportContext2D.OnElementEnd2D()
* IExportContext2D.OnFaceEdge2D()
* IExportContext2D.OnFaceSilhouette2D()
To access data for various 2D exported objects, use the classes:
* ElementNode
* FaceEdgeNode
* FaceSilhouetteNode
**Note:** For 2D export in DisplayStyle.Wireframe, Geometric object methods (OnCurve, OnFaceEdge2D, OnFaceSilhouette2D) are called regardless of the object being eventually output, i.e., even if it is occluded by another element.
**Notes** for DisplayStyle.HLR:
* Tessellated geometry methods (OnLineSegment and OnPolylineSegments) are called regardless of the return value of the respective geometric object methods (OnCurve, OnFaceEdge2D, OnFaceSilhouette2D).
* None of these methods are called between the respective pairs of calls OnInstanceBegin/OnInstanceEnd or OnLinkBegin/OnLinkEnd. They are called between OnElementBegin2D/OnElementEnd2D and OnViewBegin/OnViewEnd.
For an example of the use of the API for custom export of 2D views, see the SDK sample CustomExporter/Custom2DExporter.
### CustomExporter events
Subscribe to these events to be notified when Revit is just about to export, or has just exported, one or more views of the document via an export context by CustomExporter:
* `Autodesk.Revit.ApplicationServices.Application.ViewsExportingByContext`
* `Autodesk.Revit.ApplicationServices.Application.ViewsExportedByContext`
`Autodesk.Revit.DB.Events.ViewsExportingByContextEventArg` provides information when Revit is just about to export one or more views of the document via an export context by CustomExporter. It has the method `ViewsExportingByContextEventArgs.GetViewIds()` to get the ids of views about to be exported by CustomExporter.
`Autodesk.Revit.DB.Events.ViewsExportedByContextEventArgs` provides information when Revit has just exported one or more views of the document via an export context by CustomExporter. It has the method `ViewsExportedByContextEventArgs.GetViewIds()` \- Gets the ids of views that have been exported by CustomExporter.
## IExportContext
An instance of the IExportContext class is passed in as a parameter of the CustomExporter constructor. The methods of this interface are then called as the entities of the model are exported.
Although it is possible to create classes derived from the IExportContext class, it is preferred to use one of its derived classes: IPhotoRenderContext or IModelExportContext. When using an IPhotoRenderContext to perform a custom export, Revit will traverse the model and output the model's geometry as if processing the Render command invoked via the UI. Only elements that have actual geometry and are suitable to appear in a rendered view will be processed and output.
The IModelExportContext should be used for processing elements in the view in the same manner that Revit processes them in 3D views. This context supports additional elements including model curves and text as shown in the 3D views.
## RenderNode classes
RenderNode is the base class for all output nodes in a model-exporting process. A node can be either geometric (such as an element or light) or non-geometric (such as material). Some types of nodes are container nodes, which include other render nodes.
## CameraInfo
The CameraInfo class describes information about projection mapping of a 3D view to a rendered image. An instance of this class can be obtained via a property of ViewNode. If it is null, an orthographic view should be assumed.
**Parent page:** [Export](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Export_html.html)

View File

@@ -0,0 +1,59 @@
# Export Tables
# Export Tables
The classes listed in the table below expose read and write access to the tables used for mapping on export to various formats such as DWG and DGN. Each class contains (key, info) pairs of mapping data.
**Class** | **Description**
---|---
ExportLayerTable | Represents a table supporting a mapping of various layer properties (Category, name, color name) to layer name in the target export format.
ExportLinetypeTable | Represents a table supporting a mapping of linetype names in the target export format.
ExportPatternTable | Represents a table supporting a mapping of FillPattern names and ids to FillPattern names in the target export format.
ExportFontTable | Represents a table s upporting a mapping of font names in the target export format.
ExportLineweightTable | Represents a table s upporting a mapping of lineweight names in the target export format.
Most of these tables are available through the BaseExportOptions class (the base class for options for DGN, DXF and DWG formats). The ExportLineweightTable is available from the DGNExportOptions class. Each table has a corresponding Get and Set method. To modify the mappings, get the corresponding table, make changes and then set it back to the options class.
The following example modifies the ExportLayerTable prior to exporting a DWG file.
**Code Region: Export DWG with modified ExportLayerTable**
---
public bool ExportDWGModifyLayerTable(Document document, View view)
{
bool exported = false;
IList<string> setupNames = BaseExportOptions.GetPredefinedSetupNames(document);
if (setupNames.Count > 0)
{
// Get the export options for the first predefined setup
DWGExportOptions dwgOptions = DWGExportOptions.GetPredefinedOptions(document, setupNames[0]);
// Get the export layer table
ExportLayerTable layerTable = dwgOptions.GetExportLayerTable();
// Find the first mapping for the Ceilings category
string category = "Ceilings";
ExportLayerKey targetKey = layerTable.GetKeys().First<ExportLayerKey>(layerKey => layerKey.CategoryName == category);
ExportLayerInfo targetInfo = layerTable[targetKey];
// change the color name and cut color number for this mapping
targetInfo.ColorName = "31";
targetInfo.CutColorNumber = 31;
// Set the change back to the map
layerTable[targetKey] = targetInfo;
// Set the modified table back to the options
dwgOptions.SetExportLayerTable(layerTable);
ICollection<ElementId> views = new List<ElementId>();
views.Add(view.Id);
exported = document.Export(Path.GetDirectoryName(document.PathName),
Path.GetFileNameWithoutExtension(document.PathName), views, dwgOptions);
}
return exported;
}
**Parent page:** [Export](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Export_html.html)

View File

@@ -0,0 +1,43 @@
# IFC Export
# IFC Export
The Revit API allows custom applications to override the default implementation for the IFC export process.
When an IExporterIFC object is registered with Revit, it will be used both when the user invokes an export to IFC from the UI as well as from the API method Document.Export(String, String, IFCExportOptions). In both cases, if no custom IFC exporter if registered, the default Revit implementation for IFC export is used.
When invoking an IFC export from the API, IFCExportOptions can be used to set the same export options as are available to the user from the Export IFC dialog box.
The functions:
* IFCImportOptions.GetExtraOptions()
* IFCImportOptions.SetExtraOptions()
allow for passing in arbitrary options for custom IFC importers. Users can pass in a string to string map specifying extra data they wish to pass for IFC import.
### IExporterIFC
The interface IExporterIFC has only one method to implement, ExportIFC(). This method is invoked by Revit to perform an export to IFC. An ExporterIFC object is passed to this method as one of its parameters. ExporterIFC is the main class provided by Revit to allow implementation of an IFC export. It contains information on the options selected by the user for the export operation, as well as members used to access specific types of data needed to implement the export properly.
The Autodesk.Revit.DB.IFC namespace contains numerous IFC related API classes that can be utilized by a custom implementation of the IFC export process. For a complete sample of a custom IFC export application, see the Open Source example at <http://sourceforge.net/projects/ifcexporter/>.
## ExporterIFC utilities
The method ExporterIFC. GetFamilyInstanceAssemblyOffset (FamilyInstance) returns the translation for the family instance's adjustment within an Assembly.
## IFC Parameter Mapping
The classes and enums:
* Autodesk.Revit.DB.IFCParameterTemplate
* Autodesk.Revit.DB.IFCPropertyMappingInfo
* Autodesk.Revit.DB.PropertySelectionType
* Autodesk.Revit.DB.PropertySetupType
allow control over the way that Revit parameters are mapped to IFC properties, including the ability to create, retrieve and modify IFC parameter mapping templates.
**Parent page:** [Export](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Export_html.html)

View File

@@ -0,0 +1,143 @@
# Export
# Export
The Revit API allows for a Revit document, or a portion thereof, to be exported to various formats for use with other software. The Document class has an overloaded Export() method that will initiate an export of a document using the built-in exporter in Revit (when available). For more advanced needs, some types of exports can be customized with a Revit add-in, such as export to IFC and export to Navisworks. (Note, Navisworks export is only available as an add-in exporter).
The Document.Export() method overloads are outlined in the table below.
**Table: Document.Export() Methods**
**Format** | **Export() parameters** | **Comments**
---|---|---
gbXML | String, String, GBXMLExportOptions | Exports a gbXML file from a mass model document
gbXML | String, String, GBXMLExportOptions | Exports the document in Green-Building XML format. If EnergyDataSettings is set to use conceptual models, this function cannot be used: instead use the method above.
IFC | String, String, IFCExportOptions | Exports the document to the Industry Standard Classes (IFC) format.
NWC | String, String, NavisworksExportOptions | Exports a Revit project to the Navisworks .nwc format. Note that in order to use this function,you must have a compatible Navisworks exporter add-in registered with your session of Revit.
DWF | String, String, ViewSet, DWFExportOptions | Exports the current view or a selection of views in DWF format.
DWFX | String, String, ViewSet, DWFXExportOptions | Exports the current view or a selection of views in DWFX format.
FBX | String, String, ViewSet, FBXExportOptions | Exports the document in 3D-Studio Max (FBX) format.
DGN | String, String, ICollection(ElementId), DGNExportOptions | Exports a selection of views in DGN format.
DWG | String, String, ICollection(ElementId), DWGExportOptions | Exports a selection of views in DWG format.
DXF | String, String, ICollection(ElementId), DXFExportOptions | Exports a selection of views in DXF format.
SAT | String, String, ICollection(ElementId), SATExportOptions | Exports the current view or a selection of views in SAT format.
PDF | String, IList(ElementId), PDFExportOptions | Exports a selection of views in PDF format.
#### Exporting to gbXML
There are two methods for exporting to the Green Building XML format. The one whose last parameter is GBXMLExportOptions is only available for projects containing one or more instances of Conceptual Mass families. The GBXMLExportOptions object to pass into this method can be constructed with just the ids of the mass zones to analyze in the exported gbXML, or with the mass zone ids and the ids of the masses to use as shading surfaces in the exported gbXML. Whe using masses, they must not have mass floors or mass zones so as not to end up with duplicate surface information in the gbXML output.
The GBXMLExportOptions object used for the other gbXML export option has no settings to specify. It uses all default settings. Note that this method does not generate the energy model. The main energy model must already be stored in the document before this export is invoked.
#### Exporting to IFC
Calling Document.Export() using the IFC option will either use the default Revit IFC export implementation or a custom [IFC Export](./Export/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Export_IFC_Export_html.html), if one has been registered with the current session of Revit. In either case, the IFCExportOptions class is used to set export options such as whether to export IFC standard quantities currently supported by Revit or to allow division of multi-level walls and columns by levels.
#### Exporting to Navisworks
The Export method for Navisworks requires a compatible Navisworks exporter add-in registered with the current Revit session. If there is no compatible exporter registered, the method will throw an exception. Use the OptionalFunctionalityUtils.IsNavisworksExporterAvailable() method to determine if a Navisworks exporter is registered.
The NavisworksExportOptions object can be used to set numerous export settings for exporting to Navisworks, such as whether to divide the file into levels and whether or not to export room geometry. Additionally, the NavisworksExportOptions.ExportScope property specifieds the export scope. The default is Model. Other options include View and SelectedElements. When set to View, the NavisworksExportOptions . ViewId property should be set accordingly. This property is only used when the export scope is set to View. When set to SelectedElements, the NavisworksExportOptions . SetSelectedElementIds() method should be called with the ids of the elements to be exported.
#### Exporting to DWF and DWFX
Both DWF and DWFX files can be exported using the corresponding Document.Export() overloads. Both methods have a ViewSet parameter that represents the views to be exported. All the views in the ViewSet must be printable in order for the export to succeed. This can be checked using the View.CanBePrinted property of each view. The last parameter is either DWFExportOptions or DWFXExportOptions. DWFXExportOptions is derived from DWFExportOptions and has all the same export settings. Options include whether or not to export the crop box, the image quality whether or not to export textures to 3D DWF files, and the paper format.
**Code Region: Export DWF**
---
public bool ExportViewToDWF(Document document, View view, string pathname)
{
DWFExportOptions dwfOptions = new DWFExportOptions();
// export with crop box and area and room geometry
dwfOptions.CropBoxVisible = true;
dwfOptions.ExportingAreas = true;
dwfOptions.ExportTexture = false;
ViewSet views = new ViewSet();
views.Insert(view);
return (document.Export(Path.GetDirectoryName(pathname),
Path.GetFileNameWithoutExtension(pathname), views, dwfOptions));
}
#### Exporting to 3D-Studio Max
FBX Export requires the presence of certain modules that are optional and may not be part of the installed Revit, so the OptionalFunctionalityUtils . IsFBXExportAvailable() method reports whether the FBX Export functionality is available. The Export() method for exporting to 3D-Studio Max has a ViewSet parameter representing the set of views to export. Only 3D views are allowed. The FBXExportOptions parameter can be used to specify whether to export without boundary edges, wther to use levels of detail, and whether the export process should stop when a view fails to export.
#### Exporting to CAD Formats
Exporting to DGN , DWG and DXF format files have similar export methods and options.
DGN , DWG and DXF Export all require the presence of certain modules that are optional and may not be part of the installed version of Revit, so the OptionalFunctionalityUtils class as corresponding methods to reports whether the each of these types of export functionality are available.
The Export() methods for exporting to DGN, DWG and DXF formats all have a parameter representing the views to be exported (as an ICollection of the ElementIds of the views). At least one valid view must be present and it must be printable for the export to succeed. This can be checked using the View.CanBePrinted property of each view.
The export options for each of these formats derives from BaseExportOptions, so there are many export settings in common, such as the color mode or whether or not to hide the scope box. BaseExportOptions also has a static method called GetPredefinedSetupNames() which will return any predefined setups for a document. The name of a predefined setup can then be passed into the static method GetPredefinedOptions() available from the corresponding options class: DWGExportOptions, DGNExportOptions or DXFExportOptions. The export options for DWG and DXF files have even more options in common as they share the base class ACADExportOptions.
The following example exports the active view (if it can be printed) to a DGN file using the first predefined setup name and the predefined options, without making any changes.
**Code Region: Export DGN**
---
public bool ExportDGN(Document document, View view)
{
bool exported = false;
// Get predefined setups and export the first one
IList<string> setupNames = BaseExportOptions.GetPredefinedSetupNames(document);
if (setupNames.Count > 0)
{
// Get predefined options for first predefined setup
DGNExportOptions dgnOptions = DGNExportOptions.GetPredefinedOptions(document, setupNames[0]);
// export the active view if it is printable
if (document.ActiveView.CanBePrinted == true)
{
ICollection<ElementId> views = new List<ElementId>();
views.Add(view.Id);
exported = document.Export(Path.GetDirectoryName(document.PathName),
Path.GetFileNameWithoutExtension(document.PathName), views, dgnOptions);
}
}
return exported;
}
For these file types it is possible to specify or modify various mapping settings, such as layer mapping or text font mapping by creating the corresponding table and passing it into the appropriate method of the BaseExportOptions class. For layer mapping, you may alternatively pass in a string value to BaseExportOptions.LayerMapping of a predefined layer mapping style or the filename of a layer mapping file. For more information on creating or modifying export tables, see the [Export Tables](./Export/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Export_Export_Tables_html.html) topic.
#### Exporting to SAT
The Export method for SAT has a parameter representing the views to be exported (as an ICollection of the ElementIds of the views). At least one valid view must be present and it must be printable for the export to succeed. This can be checked using the View.CanBePrinted property of each view. The SATExportOptions object has no settings to specify. It uses all default settings.
#### Exporting to Civil Engineering Design Applications
The last Export() method exports a 3D view of the document in the format of Civil Engineering design applications. One parameter of the method is a Viewplan that specifies the gross area plan. All the areas on the view plan will be exported and it must be 'Gross Building' area plan. To check whether its area scheme is Gross Building, use the AreaScheme.GrossBuildingArea property. The BuildingSiteExportOptions object allows custom values for settings such as gross area or total occupancy.
#### Exporting to PDF
**Code Region: Print all sheets to PDF**
private void PDFExport(Document doc)
{
PDFExportOptions opt = new PDFExportOptions();
opt.Combine = true;
opt.FileName = "My House";
opt.PaperFormat = ExportPaperFormat.ARCH_E;
doc.Export(
Environment.GetFolderPath(Environment.SpecialFolder.Desktop),
new FilteredElementCollector(doc)
.OfClass(typeof(ViewSheet))
.ToElementIds().ToList(),
opt);
}
**Pages in this section**
* [Export Tables](Export/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Export_Export_Tables_html.html)
* [IFC Export](Export/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Export_IFC_Export_html.html)
* [Custom Export](Export/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Export_Custom_export_html.html)
**Parent page:** [Advanced Topics](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_html.html)

View File

@@ -0,0 +1,159 @@
# External Events
# External Events
The Revit API provides an External Events framework to accommodate the use of modeless dialogs. It is tailored for asynchronous processing and operates similarly to the Idling event with default frequency.
To implement a modeless dialog using the External Events framework, follow these steps:
1. Implement an external event handler by deriving from the IExternalEventHandler interface.
2. Create an ExternalEvent using the static ExternalEvent.Create() method.
3. When an event occurs in the modeless dialog where a Revit action needs to be taken, call ExternalEvent.Raise().
4. Revit will call the implementation of the IExternalEventHandler.Execute() method when there is an available Idling time cycle.
### IExternalEventHandler
This is the interface to be implemented for an external event. An instance of a class implementing this interface is registered with Revit, and every time the corresponding external event is raised, the Execute method of this interface is invoked.
The IExternalEventHandler has only two methods to implement, the Execute() method and GetName() which should return the name of the event. Below is a basic implementation which will display a TaskDialog when the event is raised.
**Code Region: Implementing IExternalEventHandler**
---
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
The ExternalEvent class is used to create an ExternalEvent. An instance of this class will be returned to an external event's owner upon the event's creation. The event's owner will use this instance to signal that the event should be called by Revit. Revit will periodically check if any of the events have been signaled (raised), and will execute all events that were raised by calling the Execute method on the events' respective handlers.
The following example shows the implementation of an IExternalApplication that has a method ShowForm() that is called from an ExternalCommand (shown at the end of the code region). The ShowForm() method creates a new instance of the external events handler from the example above, creates a new ExternalEvent and then displays the modeless dialog box which will later use the passed in ExternalEvent object to raise events.
**Code Region: Create the ExternalEvent**
---
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;
}
}
}
### Raise Event
Once the modeless dialog is displayed, the user may interact with it. Actions in the dialog may need to trigger some action in Revit. When this happens, the ExternalEvent.Raise() method is called. The following example is the code for a simple modeless dialog with two buttons: one to raise our event and one to close the dialog.
**Code Region: Raise the Event**
---
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();
}
}
When the ExternalEvent.Raise() method is called, Revit will wait for an available Idling timecycle and then call the IExternalEventHandler.Execute() method. In this simple example, it will display a TaskDialog with the text "Click Close to close." as shown in the first code region above.
For a more complex example of using the External Events framework, see the sample code in the SDK under the ModelessDialog\ModelessForm_ExternalEvent folder. It uses a modeless dialog with numerous buttons and the IExternalEventHandler implementation has a public property to track which button was pressed so it can switch on that value in the Execute() method.
**Parent page:** [Advanced Topics](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_html.html)

View File

@@ -0,0 +1,250 @@
# Handling Failures
# Handling Failures
Normally posted failures are processed by Revit's standard failure resolution UI at the end of a transaction (specifically when Transaction.Commit() or Transaction.Rollback() are invoked). The user is presented information and options to deal with the failures.
If an operation (or set of operations) on the document requires some special treatment from a Revit add-in for certain errors, failure handling can be customized to carry out this resolution. Custom failure handling can be supplied:
* For a given transaction using the interface IFailuresPreprocessor.
* For all possible errors using the FailuresProcessing event.
Finally, the API offers the ability to completely replace the standard failure processing user interface using the interface IFailuresProcessor. Although the first two methods for handling failures should be sufficient in most cases, this last option can be used in special cases, such as to provide a better failure processing UI or when an application is used as a front-end on top of Revit.
### Overview of Failure Processing
It is important to remember there are many things happening between the call to Transaction.Commit() and the actual processing of failures. Auto-join, overlap checks, group checks and workset editability checks are just to name a few. These checks and changes may make some failures disappear or, more likely, can post new failures. Therefore, conclusions cannot be drawn about the state of failures to be processed when Transaction.Commit() is called. To process failures correctly, it is necessary to hook up to the actual failures processing mechanism.
When failures processing begins, all changes to a document that are supposed to be made in the transaction are made, and all failures are posted. Therefore, no uncontrolled changes to a document are allowed during failures processing. There is a limited ability to resolve failures via the restricted interface provided by FailuresAccessor. If this has happened, all end of transaction checks and failures processing have to be repeated. So there may be a few failure resolution cycles at the end of one transaction.
Each cycle of failures processing includes 3 steps:
1. Preprocessing of failures (FailuresPreprocessor)
2. Broadcasting of failures processing event (FailuresProcessing event)
3. Final processing (FailuresProcessor)
Each of these 3 steps can control what happens next by returning different FailureProcessingResults. The options are:
* _**Continue**_ \- has no impact on execution flow. If FailuresProcessor returns "Continue" with unresolved failures, Revit will instead act as if "ProceedWithRollBack" was returned.
* _**ProceedWithCommit**_ \- interrupts failures processing and immediately triggers another loop of end-of-transaction checks followed by another failures processing. Should be returned after an attempt to resolve failures. Can easily lead to an infinite loop if returned without any successful failure resolution. Cannot be returned if transaction is already being rolled back and will be treated as "ProceedWithRollBack" in this case.
* _**ProceedWithRollback**_ \- continues execution of failure processing, but forces transaction to be rolled back, even if it was originally requested to commit. If before ProceedWithRollBack is returned FailureHandlingOptions are set to clear errors after rollback, no further error processing will take place, all failures will be deleted and transaction is rolled back silently. Otherwise default failure processing will continue, failures may be delivered to the user, but transaction is guaranteed to be rolled back.
* _**WaitForUserInput**_ \- can be returned only by FailuresProcessor if it is waiting for an external event (typically user input) to complete failures processing.
Depending on the severity of failures posted in the transaction and whether the transaction is being committed or rolled back, each of these 3 steps may have certain options to resolve errors. All information about failures posted in a document, information about ability to perform certain operations to resolve failures and API to perform such operations are provided via the FailuresAccessor class. The Document can be used to obtain additional information, but it cannot be changed other than via FailuresAccessor.
### FailuresAccessor
A FailuresAccessor object is passed to each of failure processing steps as an argument and is the only available interface to fetch information about failures in a document. While reading from a document during failure processing is allowed, the only way to modify a document during failure resolution is via methods provided by this class. After returning from failure processing, the instance of the class is deactivated and cannot be used any longer.
#### Information Available from FailuresAccessor
The FailuresAccessor object offers some generic information such as:
* Document for which failures are being processed or preprocessed
* Highest severity of failures posted in the document
* Transaction name and failure handling options for transaction being finished
* Whether transaction was requested to be committed or rolled back
The FailuresAccessor object also offers information about specific failures via the GetFailuresMessages() method.
#### Options to resolve failures
The FailuresAccessor object provides a few ways to resolve failures:
* Failure messages with a severity of Warning can be deleted with the DeleteWarning() or DeleteAllWarnings() methods.
* ResolveFailure() or ResolveFailures() methods can be used to resolve one or more failures using the last failure resolution type set for each failure.
* DeleteElements() can resolve failures by deleting elements related to the failure.
* Or delete all failure messages and replace them with one "generic" failure using the ReplaceFailures() method.
## IFailuresPreprocessor
The IFailuresPreprocessor interface can be used to provide custom failure handling for a specific transaction only. IFailuresPreprocessor is an interface that may be used to perform a preprocessing step to either filter out anticipated transaction failures or to post new failures. Failures can be "filtered out" by:
* silently removing warnings that are known to be posted for the transaction and are deemed as irrelevant for the user in the context of a particular transaction
* silently resolving certain failures that are known to be posted for the transaction and that should always be resolved in a context of a given transaction
* silently aborting the transaction in cases where "imperfect" transactions should not be committed or aborting the transaction is preferable over user interaction for a given workflow
The IFailuresPreprocessor interface gets control first during the failure resolution process. It is nearly equivalent to checking and resolving failures before finishing a transaction, except that IFailuresPreprocessor gets control at the right time, after all failures guaranteed to be posted and/or after all irrelevant ones are deleted.
There may be only one IFailuresPreprocessor per transaction and there is no default failure preprocessor. If one is not attached to the transaction (via the failure handling options), this first step of failure resolution is simply omitted.
**Code Region 26-3: Handling failures from IFailuresPreprocessor**
---
public class SwallowTransactionWarning : IExternalCommand
{
public Autodesk.Revit.UI.Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
Autodesk.Revit.ApplicationServices.Application app =
commandData.Application.Application;
Document doc = commandData.Application.ActiveUIDocument.Document;
UIDocument uidoc = commandData.Application.ActiveUIDocument;
FilteredElementCollector collector = new FilteredElementCollector(doc);
ICollection<Element> elementCollection =
collector.OfClass(typeof(Level)).ToElements();
Level level = elementCollection.Cast<Level>().ElementAt<Level>(0);
Transaction t = new Transaction(doc);
t.Start("room");
FailureHandlingOptions failOpt = t.GetFailureHandlingOptions();
failOpt.SetFailuresPreprocessor(new RoomWarningSwallower());
t.SetFailureHandlingOptions(failOpt);
doc.Create.NewRoom(level, new UV(0, 0));
t.Commit();
return Autodesk.Revit.UI.Result.Succeeded;
}
}
public class RoomWarningSwallower : IFailuresPreprocessor
{
public FailureProcessingResult PreprocessFailures(FailuresAccessor failuresAccessor)
{
IList<FailureMessageAccessor> failList = new List<FailureMessageAccessor>();
// Inside event handler, get all warnings
failList = failuresAccessor.GetFailureMessages();
foreach (FailureMessageAccessor failure in failList)
{
// check FailureDefinitionIds against ones that you want to dismiss,
FailureDefinitionId failID = failure.GetFailureDefinitionId();
// prevent Revit from showing Unenclosed room warnings
if (failID == BuiltInFailures.RoomFailures.RoomNotEnclosed)
{
failuresAccessor.DeleteWarning(failure);
}
}
return FailureProcessingResult.Continue;
}
}
### FailuresProcessing Event
The FailuresProcessing event is most suitable for applications that want to provide custom failure handling without a user interface, either for the entire session or for many unrelated transactions. Some use cases for handling failures via this event are:
* automatic removal of certain warnings and/or automatic resolving of certain errors based on office standards (or other criteria)
* custom logging of failures
The FailuresProcessing event is raised after IFailuresPreprocessor (if any) has finished. It can have any number of handlers, and all of them will be invoked. Since event handlers have no way to return a value, the SetProcessingResult() on the event argument should be used to communicate status. Only Continue, ProceedWithRollback or ProceedWithCommit can be set.
The following example shows an event handler for the FailuresProcessing event.
**Code Region 26-4: Handling the FailuresProcessing Event**
---
private void CheckWarnings(object sender, FailuresProcessingEventArgs e)
{
FailuresAccessor fa = e.GetFailuresAccessor();
IList<FailureMessageAccessor> failList = new List<FailureMessageAccessor>();
failList = fa.GetFailureMessages(); // Inside event handler, get all warnings
foreach (FailureMessageAccessor failure in failList)
{
// check FailureDefinitionIds against ones that you want to dismiss,
FailureDefinitionId failID = failure.GetFailureDefinitionId();
// prevent Revit from showing Unenclosed room warnings
if (failID == BuiltInFailures.RoomFailures.RoomNotEnclosed)
{
fa.DeleteWarning(failure);
}
}
}
### FailuresProcessor
The IFailuresProcessor interface gets control last, after the FailuresProcessing event is processed. There is only one active IFailuresProcessor in a Revit session. To register a failures processor, derive a class from IFailuresProcessor and register it using the Application.RegisterFailuresProcessor() method. If there is previously registered failures processor, it is discarded. If a Revit add-in opts to register a failures processor for Revit that processor will become the default error handler for all Revit errors for the session and the standard Revit error dialog will not appear. If no failures processors are set, there is a default one in the Revit UI that invokes all regular Revit error dialogs. FailuresProcessor should only be overridden to replace the existing Revit failure UI with a custom failure resolution handler, which can be interactive or have no user interface.
If the RegisterFailuresProcessor() method is passed NULL, any transaction that has any failures is silently aborted (unless failures are resolved by first two steps of failures processing).
The IFailuresProcessor.ProcessFailures() method is allowed to return WaitForUserInput, which leaves the transaction pending. It is expected that in this case, FailuresProcessor leaves some UI on the screen that will eventually commit or rollback a pending transaction - otherwise the pending state will last indefinitely, essentially freezing the document.
The following example of implementing the IFailuresProcessor checks for a failure, deletes the failing elements and sets an appropriate message for the user.
**Code Region 26-5: IFailuresProcessor**
---
[Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
public class MyFailuresUI : IExternalApplication
{
static AddInId m_appId = new AddInId(new Guid("9F179363-B349-4541-823F-A2DDB2B86AF3"));
public Autodesk.Revit.UI.Result OnStartup(UIControlledApplication uiControlledApplication)
{
IFailuresProcessor myFailUI = new FailUI();
Autodesk.Revit.ApplicationServices.Application.RegisterFailuresProcessor(myFailUI);
return Result.Succeeded;
}
public Autodesk.Revit.UI.Result OnShutdown(UIControlledApplication application)
{
return Result.Succeeded;
}
public class FailUI : IFailuresProcessor
{
public void Dismiss(Document document)
{
// This method is being called in case of exception or document destruction to
// dismiss any possible pending failure UI that may have left on the screen
}
public FailureProcessingResult ProcessFailures(FailuresAccessor failuresAccessor)
{
IList<FailureResolutionType> resolutionTypeList =
new List<FailureResolutionType>();
IList<FailureMessageAccessor> failList = new List<FailureMessageAccessor>();
// Inside event handler, get all warnings
failList = failuresAccessor.GetFailureMessages();
string errorString = "";
bool hasFailures = false;
foreach (FailureMessageAccessor failure in failList)
{
// check how many resolutions types were attempted to try to prevent
// entering infinite loop
resolutionTypeList =
failuresAccessor.GetAttemptedResolutionTypes(failure);
if (resolutionTypeList.Count >= 3)
{
TaskDialog.Show("Error", "Cannot resolve failures - transaction will be rolled back.");
return FailureProcessingResult.ProceedWithRollBack;
}
errorString += "IDs ";
foreach (ElementId id in failure.GetFailingElementIds())
{
errorString += id + ", ";
hasFailures = true;
}
errorString += "\nWill be deleted because: " + failure.GetDescriptionText() + "\n";
failuresAccessor.DeleteElements(
failure.GetFailingElementIds() as IList<ElementId>);
}
if (hasFailures)
{
TaskDialog.Show("Error", errorString);
return FailureProcessingResult.ProceedWithCommit;
}
return FailureProcessingResult.Continue;
}
}
}
**Parent page:** [Failure Posting and Handling](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Failure_Posting_and_Handling_html.html)

View File

@@ -0,0 +1,164 @@
# Posting Failures
# Posting Failures
To use the failure posting mechanism to report problems, the following steps are required:
1. New failures not already defined in Revit must be defined and registered in the FailureDefinitionRegistry during the OnStartup() call of the ExternalApplication.
2. Find the failure definition id, either from the BuiltInFailures classes or from the pre-registered custom failures using the class related to FailureDefinition.
3. Post the failure to the document that has a problem using the classes related to FailureMessage to set options and details related to the failure.
## Defining and registering a failure
Each possible failure in Revit must be defined and registered during Revit application startup by creating a FailureDefinition object that contains some persistent information about the failure such as identity, severity, basic description, types of resolution and default resolution.
The following example creates two new failures, a warning and an error, that can be used for walls that are too tall. In this example, they are used in conjunction with an Updater that will do the failure posting (in a subsequent code sample in this chapter). The FailureDefinitionIds are saved in the Updater class since they will be required when posting failures. The sections following explain the FailureDefinition.CreateFailureDefinition() method parameters in more detail.
**Code Region 26-1: Defining and registering a failure**
---
public void PostWallFailure()
{
WallWarnUpdater wallUpdater = new WallWarnUpdater(new AddInId(new Guid("F0F045A5-06E8-4C89-837D-8A8F85484953")));
UpdaterRegistry.RegisterUpdater(wallUpdater);
ElementClassFilter filter = new ElementClassFilter(typeof(Wall));
UpdaterRegistry.AddTrigger(wallUpdater.GetUpdaterId(), filter, Element.GetChangeTypeGeometry());
// define a new failure id for a warning about walls
FailureDefinitionId warnId = new FailureDefinitionId(new Guid("FB4F5AF3-42BB-4371-B559-FB1648D5B4D1"));
// register the new warning using FailureDefinition
FailureDefinition failDef = FailureDefinition.CreateFailureDefinition(warnId, FailureSeverity.Warning, "Wall is too big (>100'). Performance problems may result.");
FailureDefinitionId failId = new FailureDefinitionId(new Guid("691E5825-93DC-4f5c-9290-8072A4B631BC"));
FailureDefinition failDefError = FailureDefinition.CreateFailureDefinition(failId, FailureSeverity.Error, "Wall is WAY too big (>200'). Performance problems may result.");
// save ids for later reference
wallUpdater.WarnId = warnId;
wallUpdater.FailureId = failId;
}
#### FailureDefinitionId
A unique FailureDefinitionId must be used as a key to register the FailureDefinition. Each unique FailureDefinitionId should be created using a GUID generation tool. Later, the FailureDefinitionId can be used to look up a FailureDefinition in FailureDefinitionRegistry, and to create and post FailureMessages.
#### Severity
When registering a new failure, a severity is specified, along with the FailureDefinitionId and a text description of the failure that can be displayed to the user. The severity determines what actions are allowed in a document and whether the transaction can be committed at all. The severity options are:
* _**Warning**_ \- Failure that can be ignored by end-user. Failures of this severity do not prevent transactions from being committed. This severity should be used when Revit needs to communicate a problem to the user, but the problem does not prevent the user from continuing to work on the document
* _**Error**_ \- Failure that cannot be ignored. If FailureMeassage of this severity is posted, the current transaction cannot be committed unless the failure is resolved via an appropriate FailureResolution. This severity should be used when work on the document cannot be continued unless the problem is resolved. If the failure has no predefined resolutions available or these resolutions fail to resolve the problem, the transaction must be aborted in order to continue working with the document. It is strongly encouraged to have at least one resolution in each failure of this severity.
* _**DocumentCorruption**_ \- Failure that forces the Transaction to be rolled back as soon as possible due to known corruption to a document. When failure of this severity is posted, reading of information from a document is not allowed. The current transaction must be rolled back first in order to work with the document. This severity is used only if there is known data corruption in the document. This type of failure should generally be avoided unless there is no way to prevent corruption or to recover from it locally.
A fourth severity, None, cannot be specified when defining a new FailureDefinition.
The method LabelUtils.GetFailureSeverityName() returns the user-visible name for the severity of a warning.
#### Failure Resolutions
When a failure can be resolved, all possible resolutions should be predefined in the FailureDefinition class. This informs Revit what failure resolutions can possibly be used with a given failure. The FailureDefinition contains a full list of resolution types applicable to the failure, including a user-visible caption of the resolution.
The number of resolutions is not limited, however as of the 2011 Revit API, the only exposed failure resolution is DeleteElements. When more than one resolution is specified, unless explicitly changed using the SetDefaultResolutionType() method, the first resolution added becomes the default resolution. The default resolution is used by the Revit failure processing mechanism to resolve failures automatically when applicable. The Revit UI only uses the default resolution, but Revit add-ins, via the Revit API, can use any applicable resolution, and can provide an alternative UI for doing that (as described in the Handling Failures section later in this chapter).
In the case of a failure with a severity of DocumentCorruption, by the time failure resolution could occur, the transaction is already aborted, so there is nothing to resolve. Therefore, FailureResolutions should not be added to API-defined Failures of severity DocumentCorruption.
### Posting a failure
The Document.PostFailure() method is used to notify the document of a problem. Failures will be validated and possibly resolved at the end of the transaction. Warnings posted via this method will not be stored in the document after they are resolved. Failure posting is used to address a state of the document which may change before the end of the transaction or when it makes sense to defer resolution until the end of the transaction. Not all failures encountered by an external command should post a failure. If the failure is unrelated to the document, a task dialog should be used. For example, if the Revit UI is in an invalid state to perform the external command.
To post a failure, create a new FailureMessage using the FailureDefinitionId from when the custom failure was defined, or use a BuiltInFailure provided by the Revit API. Set any additional information in the FailureMessage object, such as failing elements, and then call Document.PostFailure() passing in the new FailureMessage. Note that the document must be modifiable in order to post a failure.
A unique FailureMessageKey returned by PostFailure() can be stored for the lifetime of transaction and used to remove a failure message if it is no longer relevant. If the same FailureMessage is posted two or more times, the same FailureMessageKey is returned. If a posted failure has a severity of DocumentCorruption, an invalid FailureMessageKey is returned. This is because a DocumentCorruption failure cannot be unposted.
The following example shows an IUpdate class (referenced in the "Defining and registering a failure" code region above) that posts a new failure based on information received in the Execute() method.
**Code Region 26-2: Posting a failure**
---
public class WallWarnUpdater : IUpdater
{
static AddInId m_appId;
UpdaterId m_updaterId;
FailureDefinitionId m_failureId = null;
FailureDefinitionId m_warnId = null;
// constructor takes the AddInId for the add-in associated with this updater
public WallWarnUpdater(AddInId id)
{
m_appId = id;
m_updaterId = new UpdaterId(m_appId,
new Guid("69797663-7BCB-44f9-B756-E4189FE0DED8"));
}
public void Execute(UpdaterData data)
{
Document doc = data.GetDocument();
Autodesk.Revit.ApplicationServices.Application app = doc.Application;
foreach (ElementId id in data.GetModifiedElementIds())
{
Wall wall = doc.GetElement(id) as Wall;
Autodesk.Revit.DB.Parameter p = wall.LookupParameter("Unconnected Height");
if (p != null)
{
if (p.AsDouble() > 200)
{
FailureMessage failMessage = new FailureMessage(FailureId);
failMessage.SetFailingElement(id);
doc.PostFailure(failMessage);
}
else if (p.AsDouble() > 100)
{
FailureMessage failMessage = new FailureMessage(WarnId);
failMessage.SetFailingElement(id);
doc.PostFailure(failMessage);
}
}
}
}
public FailureDefinitionId FailureId
{
get { return m_failureId; }
set { m_failureId = value; }
}
public FailureDefinitionId WarnId
{
get { return m_warnId; }
set { m_warnId = value; }
}
public string GetAdditionalInformation()
{
return "Give warning and error if wall is too tall";
}
public ChangePriority GetChangePriority()
{
return ChangePriority.FloorsRoofsStructuralWalls;
}
public UpdaterId GetUpdaterId()
{
return m_updaterId;
}
public string GetUpdaterName()
{
return "Wall Height Check";
}
}
### Removal of posted failures
Because there may be multiple changes to a document and multiple regenerations in the same transaction, it is possible that some failures are no longer relevant and they may need to be removed to prevent "false alarms". Specific messages can be un-posted by calling the Document.UnpostFailure() method and passing in the FailureMessageKey obtained when PostFailure() was called. UnpostFailure() will throw an exception if the severity of the failure is DocumentCorruption.
It is also possible to automatically remove all posted failures when a transaction is about to be rolled back (so that the user is not bothered to press Cancel) by using the Transaction.SetFailureHandlingOptions() method.
**Parent page:** [Failure Posting and Handling](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Failure_Posting_and_Handling_html.html)

View File

@@ -0,0 +1,14 @@
# Failure Posting and Handling
# Failure Posting and Handling
The Revit API provides the ability to post failures when a user-visible problem has occurred and to respond to failures posted by Revit or Revit add-ins.
**Pages in this section**
* [Posting Failures](Failure_Posting_and_Handling/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Failure_Posting_and_Handling_Posting_Failures_html.html)
* [Handling Failures](Failure_Posting_and_Handling/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Failure_Posting_and_Handling_Handling_Failures_html.html)
**Parent page:** [Advanced Topics](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_html.html)

View File

@@ -0,0 +1,155 @@
# Managing External Files
# Managing External Files
### ExternalFileUtils
As its name implies, this utility class provides information about external file references. TheExternalFileUtils.GetAllExternalFileReferences() method returns a collection of ElementIds of all elements that are external file references in the document. (Note that it will not return the ids of nested Revit links; it only returns top-level references.) This utility class has two other methods, IsExternalFileReference() and GetExternalFileReference() which perform the same function as the similarly named methods of the Element class, but can be used when you have an ElementId rather than first obtaining the Element.
TransmissionDataTransmissionData stores information on both the previous state and requested state of an external file reference. This means that it stores the load state and path of the reference from the most recent time this TransmissionData's document was opened. It also stores load state and path information for what Revit should do the next time the document is opened.
As such, TransmissionData can be used to perform operations on external file references without having to open the entire associated Revit document. The methods ReadTransmissionData and WriteTransmissionData can be used to obtain information about external references, or to change that information. For example, calling WriteTransmissionData with a TransmissionData object which has had all references set to LinkedFileStatus.Unloaded would cause no references to be loaded upon next opening the document.
TransmissionData cannot add or remove references to external files. If AddExternalFileReference is called using an ElementId which does not correspond to an element which is an external file reference, the information will be ignored on file load.
The following example reads the TransmissionData for a file at the given location and sets all Revit links to be unloaded the next time the document is opened.
**Code Region: Unload Revit Links**
---
void UnloadRevitLinks(ModelPath location)
/// This method will set all Revit links to be unloaded the next time the document at the given location is opened.
/// The TransmissionData for a given document only contains top-level Revit links, not nested links.
/// However, nested links will be unloaded if their parent links are unloaded, so this function only needs to look at the document's immediate links.
{
// access transmission data in the given Revit file
TransmissionData transData = TransmissionData.ReadTransmissionData(location);
if (transData != null)
{
// collect all (immediate) external references in the model
ICollection<ElementId> externalReferences = transData.GetAllExternalFileReferenceIds();
// find every reference that is a link
foreach (ElementId refId in externalReferences)
{
ExternalFileReference extRef = transData.GetLastSavedReferenceData(refId);
if (extRef.ExternalFileReferenceType == ExternalFileReferenceType.RevitLink)
{
// we do not want to change neither the path nor the path-type
// we only want the links to be unloaded (shouldLoad = false)
transData.SetDesiredReferenceData(refId, extRef.GetPath(), extRef.PathType, false);
}
}
// make sure the IsTransmitted property is set
transData.IsTransmitted = true;
// modified transmission data must be saved back to the model
TransmissionData.WriteTransmissionData(location, transData);
}
else
{
Autodesk.Revit.UI.TaskDialog.Show("Unload Links", "The document does not have any transmission data");
}
}
#### Construct ModelPath for location on Revit Server
To read the TransmissionData object, you need to call the static method TransmissionData.ReadTransmissionData. It requires a ModelPath object.
There are two ways to construct a ModelPath object that refers to a central file. The first way involves using ModelPathUtils and the base ModelPath class. The steps are as follows:
1. Compose the user-visible path string of the central file: `RSN://` \+ “relative path”.
Note: The folder separator used in the "relative path" is a forward slash(/). The correct separator is a forward slash.
2. Create a ModelPath object via the ModelPathUtils.ConvertUserVisiblePathToModelPath() method. Pass in the string composed in the previous step.
3. Read the transmission data via the TransmissionData::ReadTransmissionData() method. Pass in the ModelPath obtained in the previous step.
The following example demonstrates this method assuming a central file testmodel.rvt is stored in the root folder of Revit Server, SHACNG035WQRP.
**Code Region: Constructing path to central file using ModelPath**
---
[TransactionAttribute(Autodesk.Revit.Attributes.TransactionMode.Manual)]
public class RevitCommandLink : IExternalCommand
{
public Result Execute(ExternalCommandData commandData,
ref string messages, ElementSet elements)
{
UIApplication app = commandData.Application;
Document doc = app.ActiveUIDocument.Document;
Transaction trans = new Transaction(doc, "ExComm");
trans.Start();
string visiblePath = "RSN://testmodel.rvt";
ModelPath serverPath = ModelPathUtils.ConvertUserVisiblePathToModelPath(visiblePath);
TransmissionData transData = TransmissionData.ReadTransmissionData(serverPath);
string mymessage = null;
if (transData != null)
{
//access the data in the transData here.
}
else
{
Autodesk.Revit.UI.TaskDialog.Show("Unload Links",
"The document does not have any transmission data");
}
trans.Commit();
return Result.Succeeded;
}
}
The second way to construct the ModelPath object that that refers to a central file is to use the child class ServerPath. This way can be used if the program knows the local server name, however, it is not recommended as the server name may be changed by the Revit user from the Revit UI. The steps are as follows:
1. Create a ServerPath object using ServerPath constructor.
public ServerPath GetServerPath()
{
return new ServerPath("ServerNameOrServerIp", "relative path without the initial forward slash");
}
Note: The first parameter is the server name, not the "RSN://" string. The second parameter does not include the initial forward slash. See the following sample code. The folder separator is a forward slash(/) too.
2\. Read the TransmissionData object via the TransmissionData.ReadTransmissionData() method.Pass in the ServerPath obtained in the previous step
The following code demonstrates this method.
**Code Region: Constructing path to central file using ServerPath**
---
[TransactionAttribute(Autodesk.Revit.Attributes.TransactionMode.Manual)]
public class RevitCommand : IExternalCommand
{
public Result Execute(ExternalCommandData commandData,
ref string messages, ElementSet elements)
{
UIApplication app = commandData.Application;
Document doc = app.ActiveUIDocument.Document;
Transaction trans = new Transaction(doc, "ExComm");
trans.Start();
ServerPath serverPath = new ServerPath("SHACNG035WQRP", "testmodel.rvt");
TransmissionData transData = TransmissionData.ReadTransmissionData(serverPath);
string mymessage = null;
if (transData != null)
{
//access the data in the transData here.
}
else
{
Autodesk.Revit.UI.TaskDialog.Show("Unload Links",
"The document does not have any transmission data");
}
trans.Commit();
return Result.Succeeded;
}
}
**Parent page:** [Linked Files](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Linked_Files_html.html)

View File

@@ -0,0 +1,373 @@
# Revit Links
# Revit Links
Revit documents can have links to various external files, including other Revit documents. These types of links in the Revit API are represented by the RevitLinkType and RevitLinkInstance classes. The RevitLinkType class represents another Revit Document ("link") brought into the current one ("host"), while the RevitLinkInstance class represents an instance of a RevitLinkType.
### Creating New Links
To create a new Revit link, use the static RevitLinkType.Create() method which will create a new Revit link type and load the linked document and the static RevitLinkInstance.Create() method to place an instance of the link in the model. The RevitLinkType.Create() method requires a document (which will be the host), a ModelPath to the file to be linked, and a RevitLinkOptions object. The RevitLinkOptions class represents options for creating and loading a Revit link. Options include whether or not Revit will store a relative or absolute path to the linked file and the workset configuration. The WorksetConfiguration class is used to specify which, if any, worksets will be opened when creating the link. Note that the relative or absolute path determines how Revit will store the path, but the ModelPath passed into the Create() method needs a complete path to find the linked document initially.
The following example demonstrates the use of RevitLinkType.Create(). The variable pathName is the full path to the file on disk to be linked.
**Code Region: Create new Revit Link**
---
public ElementId CreateRevitLink(Document doc, string pathName)
{
FilePath path = new FilePath(pathName);
RevitLinkOptions options = new RevitLinkOptions(false);
// Create new revit link storing absolute path to file
LinkLoadResult result = RevitLinkType.Create(doc, path, options);
return (result.ElementId);
}
Once the RevitLinkType is created, instances can be added to the document. In the following example, two instances of a RevitLinkType are added, offset by 100'. Until a RevitLinkInstance is created, the Revit link will show up in the Manage Links window, but the elements of the linked file will not be visible in any views.
**Code Region: Create new Revit Link Instance**
---
public void CreateLinkInstances(Document doc, ElementId linkTypeId)
{
// Create revit link instance at origin
RevitLinkInstance.Create(doc, linkTypeId);
RevitLinkInstance instance2 = RevitLinkInstance.Create(doc, linkTypeId);
// Offset second instance by 100 feet
Location location = instance2.Location;
location.Move(new XYZ(0, -100, 0));
}
The examples above work with files on the local disk. Below is a more complex example involving a link to a model on Revit server.
**Code Region: Create new Revit Link to a model located on Revit server**
---
public static void CreateLinkToServerModel(UIApplication uiApp)
{
UIDocument uiDoc = uiApp.ActiveUIDocument;
Document doc = uiDoc.Document;
// Try to get the server path for the particular model on the server
Application application = uiApp.Application;
String hostId = application.GetRevitServerNetworkHosts().First();
String rootFolder = "|";
ModelPath serverPath = FindModelPathOnServer(application, hostId, rootFolder, "Wall pin model for updaters.rvt");
using (Transaction t = new Transaction(doc, "Create link"))
{
t.Start();
RevitLinkOptions options = new RevitLinkOptions(false);
LinkLoadResult result = RevitLinkType.Create(doc, serverPath, options);
RevitLinkInstance.Create(doc, result.ElementId);
t.Commit();
}
}
private static ModelPath FindModelPathOnServer(Application app, string hostId, string folderName, string fileName)
{
// Connect to host to find list of available models (the "/contents" flag)
XmlDictionaryReader reader = GetServerResponse(app, hostId, folderName + "/contents");
bool found = false;
// Look for the target model name in top level folder
List<String> folders = new List<String>();
while (reader.Read())
{
// Save a list of subfolders, if found
if (reader.NodeType == XmlNodeType.Element && reader.Name == "Folders")
{
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.EndElement && reader.Name == "Folders")
break;
if (reader.NodeType == XmlNodeType.Element && reader.Name == "Name")
{
reader.Read();
folders.Add(reader.Value);
}
}
}
// Check for a matching model at this folder level
if (reader.NodeType == XmlNodeType.Element && reader.Name == "Models")
{
found = FindModelInServerResponse(reader, fileName);
if (found)
break;
}
}
reader.Close();
// Build the model path to match the found model on the server
if (found)
{
// Server URLs use "|" for folder separation, Revit API uses "/"
String folderNameFragment = folderName.Replace('|', '/');
// Add trailing "/" if not present
if (!folderNameFragment.EndsWith("/"))
folderNameFragment += "/";
// Build server path
ModelPath modelPath = new ServerPath(hostId, folderNameFragment + fileName);
return modelPath;
}
else
{
// Try subfolders
foreach (String folder in folders)
{
ModelPath modelPath = FindModelPathOnServer(app, hostId, folder, fileName);
if (modelPath != null)
return modelPath;
}
}
return null;
}
// This string is different for each RevitServer version
private static string revitServerVersion = "/RevitServerAdminRESTService2014/AdminRESTService.svc/";
private static XmlDictionaryReader GetServerResponse(Application app, string hostId, string info)
{
// Create request
WebRequest request = WebRequest.Create("http://" + hostId + revitServerVersion + info);
request.Method = "GET";
// Add the information the request needs
request.Headers.Add("User-Name", app.Username);
request.Headers.Add("User-Machine-Name", app.Username);
request.Headers.Add("Operation-GUID", Guid.NewGuid().ToString());
// Read the response
XmlDictionaryReaderQuotas quotas =
new XmlDictionaryReaderQuotas();
XmlDictionaryReader jsonReader =
JsonReaderWriterFactory.CreateJsonReader(request.GetResponse().GetResponseStream(), quotas);
return jsonReader;
}
private static bool FindModelInServerResponse(XmlDictionaryReader reader, string fileName)
{
// Read through entries in this section
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.EndElement && reader.Name == "Models")
break;
if (reader.NodeType == XmlNodeType.Element && reader.Name == "Name")
{
reader.Read();
String modelName = reader.Value;
if (modelName.Equals(fileName))
{
// Match found, stop looping and return
return true;
}
}
}
return false;
}
In the example below, the WorksetConfiguration is obtained, modified so that only one specified workset is opened and set back to the RevitLinkOptions prior to creating the new link.
**Code Region: Create link with one workset open**
---
public bool CreateRevitLinkWithOneWorksetOpen(Document doc, string pathName, string worksetName)
{
FilePath path = new FilePath(pathName);
RevitLinkOptions options = new RevitLinkOptions(true);
// Get info on all the user worksets in the project prior to opening
IList<WorksetPreview> worksets = WorksharingUtils.GetUserWorksetInfo(path);
IList<WorksetId> worksetIds = new List<WorksetId>();
// Find worksetName
foreach (WorksetPreview worksetPrev in worksets)
{
if (worksetPrev.Name.CompareTo(worksetName) == 0)
{
worksetIds.Add(worksetPrev.Id);
break;
}
}
// close all worksets but the one specified
WorksetConfiguration worksetConfig = new WorksetConfiguration(WorksetConfigurationOption.CloseAllWorksets);
if (worksetIds.Count > 0)
{
worksetConfig.Open(worksetIds);
}
options.SetWorksetConfiguration(worksetConfig);
LinkLoadResult result = RevitLinkType.Create(doc, path, options);
RevitLinkType type = doc.GetElement(result.ElementId) as RevitLinkType;
return (result.LoadResult == LinkLoadResultType.LinkLoaded);
}
Whether creating or loading a link, a LinkLoadResult is returned. This class has a property to determine if the link was loaded. It also has an ElementId property that is the id of the created or loaded linked model.
RevitLinkInstance.Create(ImportPlacement placement)creates a new instance of a linked Revit project (RevitLinkType). Instances will be placed origin-to-origin or by shared coordinates according to the input placement type.
### Loading and Unloading Links
RevitLinkType has several methods related to loading links. Load(), LoadFrom() and Unload() allow a link to be loaded or unloaded, or to be loaded from a new location. These methods regenerate the document. The document's Undo history will be cleared by these methods. All transaction phases (e.g., transactions, transaction groups and sub-transactions) that were explicitly started must be finished prior to calling one of these methods.
The static method RevitLinkType.IsLoaded() will return whether or not the link is loaded.
### Getting Link Information
Each RevitLinkType in a document can have one or more associated RevitLinkInstances. The RevitLinkInstance.GetLinkDocument() method returns a Document associated with the Revit link. This document cannot be modified, meaning that operations that require a transaction or modify the document's status in memory (such as Save and Close) cannot be performed.
The associated RevitLinkType for a RevitLinkInstance can be retrieved from the document using the ElementId obtained from the RevitLinkInstance.GetTypeId() method. The RevitLinkType for a linked file has several methods and properties related to nested links. A document that is linked in to another document may itself have links. The IsNested property returns true if the RevitLinkType is a nested link (i.e. it has some other link as a parent), or false if it is a top-level link. The method GetParentId() will get the id of the immediate parent of this link, while GetRootId() will return the id of the top-level link which this link is ultimately linked under. Both methods will return invalidElementId if this link is a top-level link. The method GetChildIds() will return the element ids of all links which are linked directly into this one.
For example, if C is linked into document B and B in turn is linked into document A, calling GetParentId() for the C link will return the id of document B and calling GetRootId() for the C link will return the id of document A. Calling GetChildIds() for document A will only return the id of B's link since C is not a direct link under A.
RevitLinkType also has a PathType property which indicates if the path to the external file reference is relative to the host file's location (or to the central model's location if the host is workshared), an absolute path to a location on disk or the network, or if the path is to a Revit Server location.
The AttachmentType property of RevitLinkType indicates if the link is an attachment or an overlay. "Attachment" links are considered to be part of their parent link and will be brought along if their parent is linked into another document. "Overlay" links are only visible when their parent is opened directly.
The following example gets all RevitLinkInstances in the document and displays some information on them.
**Code Region: Getting Link information**
---
public void GetAllRevitLinkInstances(Document doc)
{
FilteredElementCollector collector = new FilteredElementCollector(doc);
collector.OfClass(typeof(RevitLinkInstance));
StringBuilder linkedDocs = new StringBuilder();
foreach (Element elem in collector)
{
RevitLinkInstance instance = elem as RevitLinkInstance;
Document linkDoc = instance.GetLinkDocument();
linkedDocs.AppendLine("FileName: " + Path.GetFileName(linkDoc.PathName));
RevitLinkType type = doc.GetElement(instance.GetTypeId()) as RevitLinkType;
linkedDocs.AppendLine("Is Nested: " + type.IsNestedLink.ToString());
}
TaskDialog.Show("Revit Links in Document", linkedDocs.ToString());
}
### Link Geometry
#### Shared coordinates
The RevitLinkType methods SavePositions() and HasSaveablePositions() support saving shared coordinates changes back to the linked document. Use HasSaveablePositions() to determine if the link has shared positioning changes which can be saved. Call SavePositions() to save shared coordinates changes back to the linked document. SavePositions() requires an instance of the ISaveSharedCoordinatesCallback interface to resolve situations when Revit encounters modified links. The interface's GetSaveModifiedLinksOption() method determines whether Revit should save the link, not save the link, or discard shared positioning entirely.
While SavePositions() does not clear the document's undo history, it cannot be undone since it saves the link's shared coordinates changes to disk.
`ResetSharedCoordinates()` resets the shared coordinates for the host model. It provides the same functionality as the UI Command "Reset Shared Coordinates". After resetting coordinates, the following changes will take place:
* GIS coordinate system will be erased.
* Shared coordinates?relationships with other linked models will be eliminated.
* The Survey Point will be moved back to the startup location, where it coincides with the Internal Origin.
* The angle between Project North and True North will be reset to 0.
Note: There will be no changes to linked models.
#### Conversion of geometric references
The Reference class has members related to linked files that allow conversion between Reference objects which reference only the contents of the link and Reference objects which reference the host. This allows an application, for example, to look at the geometry in the link, find the needed face, and convert the reference to that face into a reference in the host suitable for use to place a face-based instance. Also, these Reference members make it possible to obtain a reference in the host (e.g., from a dimension or family) and convert it to a reference in the link suitable for use in Element.GetGeometryObjectFromReference().
The Reference. LinkedElementId property represents the id of the top-level element in the linked document that is referred to by this reference, or InvalidElementId for references that do not refer to an element in a linked RVT file. The Reference . CreateLinkReference() method uses a RevitLinkInstance to create a Reference from a Reference in a Revit link. And the Reference. CreateReferenceInLink() method creates a Reference in a Revit Link from a Reference in the host file
#### Picking elements in links
The Selection methods PickObject() and PickObjects() allow the selection of objects in Revit links. To allow the user to select elements in linked files, use the ObjectType.LinkedElement enumeration value for the first parameter of the PickObject() or PickObjects(). Note that this option allows for selection of elements in links only, not in the host document.
In the example below, an ISelectionFilter is used to allow only walls to be selected in linked files.
**Code Region: Selecting Elements in Linked File**
---
public void SelectElementsInLinkedDoc(Autodesk.Revit.DB.Document document)
{
UIDocument uidoc = new UIDocument(document);
Selection choices = uidoc.Selection;
// Pick one wall from Revit link
WallInLinkSelectionFilter wallFilter = new WallInLinkSelectionFilter();
Reference elementRef = choices.PickObject(ObjectType.LinkedElement, wallFilter, "Select a wall in a linked document");
if (elementRef != null)
{
TaskDialog.Show("Revit", "Element from link document selected.");
}
}
// This filter allows selection of only a certain element type in a link instance.
class WallInLinkSelectionFilter : ISelectionFilter
{
private RevitLinkInstance m_currentInstance = null;
public bool AllowElement(Element e)
{
// Accept any link instance, and save the handle for use in AllowReference()
m_currentInstance = e as RevitLinkInstance;
return (m_currentInstance != null);
}
public bool AllowReference(Reference refer, XYZ point)
{
if (m_currentInstance == null)
return false;
// Get the handle to the element in the link
Document linkedDoc = m_currentInstance.GetLinkDocument();
Element elem = linkedDoc.GetElement(refer.LinkedElementId);
// Accept the selection if the element exists and is of the correct type
return elem != null && elem is Wall;
}
}
### Link Graphics
#### Link Visibility/Graphic Override API
This functionality allows gettings and setting the details of the 'Custom' option for the Visibility/Graphic Overrides of Revit Links.
`RevitLinkGraphicsSettings.IsViewRangeSupported(View)` Checks if the view supports view range settings for RevitLinkGraphicsSettings graphic overrides.
##### Phase
* `RevitLinkGraphicsSettings.GetPhaseId()`
* `RevitLinkGraphicsSettings.GetPhaseType()`
* `RevitLinkGraphicsSettings.GetPhaseFilterId()`
* `RevitLinkGraphicsSettings.GetPhaseFilterType()`
* `RevitLinkGraphicsSettings.SetPhase(LinkVisibility, ElementId)` Sets the phase and phase type of RevitLinkGraphicsSettings. Accepts LinkVisibility and ElementId of the phase from the linked document or ElementId.InvalidElementId.
* `RevitLinkGraphicsSettings.SetPhaseFilter(LinkVisibility, ElementId)` Sets the phase filter and phase filter type of RevitLinkGraphicsSettings. Accepts LinkVisibility and ElementId of the phase filter from the linked document or ElementId.InvalidElementId.
##### Detail Level
* `RevitLinkGraphicsSettings.GetViewDetailLevel()`
* `RevitLinkGraphicsSettings.GetViewDetailLevelType()`
* `RevitLinkGraphicsSettings.SetViewDetailLevel(LinkVisibility, ViewDetailLevel)` Sets the detail level and detail level type of RevitLinkGraphicsSettings. Accepts LinkVisibility and ViewDetailLevel types.
##### Discipline
* `RevitLinkGraphicsSettings.GetDiscipline()`
* `RevitLinkGraphicsSettings.GetDisciplineType()`
* `RevitLinkGraphicsSettings.SetDiscipline(LinkVisibility, ViewDiscipline)` Sets the discipline and discipline type of RevitLinkGraphicsSettings. Accepts LinkVisibility and ViewDiscipline types.
**Parent page:** [Linked Files](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Linked_Files_html.html)

View File

@@ -0,0 +1,62 @@
# Linked Files
# Linked Files
The Revit API can determine which elements in Revit are references to external files ("linked files") and can make some modifications to how Revit loads external files.
An Element which contains an ExternalFileReference is an element which refers to some file outside of the base .rvt file. Examples include Revit links, CAD links, the element which stores the location of the keynote file, and rendering decals. Element.IsExternalFileReference() returns whether or not an element represents an external file. And Element.GetExternalFileReference() returns the ExternalFileReference for a given Element which contains information pertaining to the external file referenced by the element.
The following classes are associated with linked files in the Revit API:
* **ExternalFileReference** \- A non-Element class which contains path and type information for a single external file which a Revit project references.
* **ExternalFileUtils** \- A utility class which allows the user to find all external file references, get the external file reference from an element, or tell whether an element is an external file reference.
* **RevitLinkType** \- An element representing a Revit file linked into a Revit project.
* **ModelPath** \- A non-Element class which contains path information for a file (not necessarily a .rvt file.) Paths can be to a location on a local or network drive, or to a Revit Server location.
* **ModelPathUtils** \- A utility class which provides methods for converting between strings and ModelPaths.
* **TransmissionData** \- A class which stores information about all of the external file references in a document. The TransmissionData for a Revit project can be read without opening the document.
`Autodesk.Revit.DB.RevitLinkGraphicsSettings` represents settings to override display of Revit link in a view.
It has methods:
* Revit.DB.View.GetLinkOverrides(ElementId) - Allows users to return settings representing graphic overrides for the input element Id in the view. Accepts ElementId of a RevitLinkType or RevitLinkInstance.
* Revit.DB.View.SetLinkOverrides(ElementId, RevitLinkGraphicsSettings) - Allows users to set graphic overrides of a RevitLinkType or RevitLinkInstance in the view.
* Revit.DB.View.RemoveLinkOverrides(ElementId) - Allows users to delete graphical link overrides in the current view. Accepts ElementId of a RevitLinkType or RevitLinkInstance.
It has properties:
* Revit.DB.RevitLinkGraphicsSettings.LinkedViewId - The id of the linked view associated with RevitLinkGraphicsSettings or the invalid element Id if no view is selected.
* Revit.DB.RevitLinkGraphicsSettings.LinkVisibilityType - The visibility type of RevitLinkGraphicsSettings.
### ModelPath
ModelPaths are paths to another file. They can refer to Revit models, or to any of Revit's external file references such as DWG links. Paths can be relative or absolute, but they must include an extension indicating the file type. Relative paths are generally relative to the currently opened document. If the current document is workshared, paths will be treated as relative to the central model. To create a ModelPath, use one of the derived classes FilePath or ServerPath.
The class ModelPathUtils contains utility functions for converting ModelPaths to and from user-visible path strings, as well as to determine if a string is a valid server path.
Shared Coordinates let the position of one linked file be known to other linked models.
* Document.AcquireCoordinates acquires the project coordinates from a specified link instance. This works for both Revit links (RevitLinkInstance) and DWG links (ImportInstance).
* Document.PublishCoordinates - Publishes shared coordinates to a specified ProjectLocation. This method works only on Revit links. These read-only properties provide information on the geographic coordinate system of a SiteLocation. The geographic coordinate system is imported from a DWG file from AutoCAD or Civil 3D. If the SiteLocation has geographic coordinate system information, the latitude and longitude of the SiteLocation will be updated automatically when the model's Survey Point is moved.
* SiteLocation.GeoCoordinateSystemId - Gets a string corresponding to geographic coordinate system ID, such as "AMG-50" or "Beijing1954/a.GK3d-40" for the SiteLocation. The value will be the empty string if there is no coordinate system specified for the SiteLocation.
* SiteLocation.GeoCoordinateSystemDefinition - Gets an XML string describing the geographic coordinate system. The value will be the empty string if there is no coordinate system specified for the SiteLocation.
**Pages in this section**
* [Revit Links](Linked_Files/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Linked_Files_Revit_Links_html.html)
* [Managing External Files](Linked_Files/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Linked_Files_Managing_External_Files_html.html)
**Parent page:** [Advanced Topics](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_html.html)

View File

@@ -0,0 +1,178 @@
# Performance Adviser
# Performance Adviser
The performance adviser feature of the Revit API is designed to analyze a document and flag for the user any elements and/or settings that may cause performance degradation. The Performance Adviser command executes a set of rules and displays their result in a standard review warnings dialog.
The API for performance adviser consists of 2 classes:
* **PerformanceAdviser** \- an application-wide object that has a dual role as a registry of rules to run in order to detect potential performance problems and an engine to execute them
* **IPerformanceAdviserRule** \- an interface that allows you to define new rules for the Performance Adviser
### Performance Adviser
PerformanceAdviser is used to add or delete rules to be checked, enable and disable rules, get information about rules in the list, and to execute some or all rules in the list. Applications that create new rules are expected to use AddRule() to register the new rule during application startup and DeleteRule() to deregister it during application shutdown. ExecuteAllRules() will execute all rules in the list on a given document, while ExecuteRules() can be used to execute selected rules in a document. Both methods will return a list of failure messages explaining performance problems detected in the document.
The following example demonstrates looping through all performance adviser rules and executing all the rules for a document.
**Code Region: Performance Adviser**
---
//Get the name of each registered PerformanceRule and then execute all of them.
public void RunAllRules(Document document)
{
foreach (PerformanceAdviserRuleId id in PerformanceAdviser.GetPerformanceAdviser().GetAllRuleIds())
{
string ruleName = PerformanceAdviser.GetPerformanceAdviser().GetRuleName(id);
}
PerformanceAdviser.GetPerformanceAdviser().ExecuteAllRules(document);
}
### IPerformanceAdviserRule
Create an instance of the IPerformanceAdviserRule interface to create new rules for the Performance Adviser. Rules can be specific to elements or can be document-wide rules. The following methods need to be implemented:
* GetName() - a short string naming the rule
* GetDescription() - a one to two sentence description of the rule
* InitCheck() -method invoked by performance advisor once in the beginning of the check. If rule checks the document as a whole rather than specific elements, the check should be performed in this method.
* FinalizeCheck() - method invoked by performance advisor once in the end of the check. Any problematic results found during rule execution can be reported during this message using FailureMessage(s)
* WillCheckElements() - indicates if rule needs to be executed on idividual elements
* GetElementFilter() - retrieves a filter to restrict elements to be checked
* ExecuteElementCheck() - method invoked by performance advisor for each element to be checked
The following excerpt from the PerformanceAdviserControl sample in the Revit API SDK Samples folder demonstrates the implementation of a custom rule used to identify any doors in the document that are face-flipped. (See the sample project for the complete class implementation.)
**Code Region: Implementing IPerformanceAdviserRule**
---
public class FlippedDoorCheck : Autodesk.Revit.DB.IPerformanceAdviserRule
{
private string m_name;
private string m_description;
private FailureDefinitionId m_doorWarningId;
private FailureDefinition m_doorWarning;
private List<ElementId> m_FlippedDoors;
#region Constructor
/// <summary>
/// Set up rule name, description, and error handling
/// </summary>
public FlippedDoorCheck()
{
m_name = "Flipped Door Check";
m_description = "An API-based rule to search for and return any doors that are face-flipped";
m_doorWarningId = new Autodesk.Revit.DB.FailureDefinitionId(new Guid("25570B8FD4AD42baBD78469ED60FB9A3"));
m_doorWarning = Autodesk.Revit.DB.FailureDefinition.CreateFailureDefinition(m_doorWarningId, Autodesk.Revit.DB.FailureSeverity.Warning, "Some doors in this project are face-flipped.");
}
#endregion
#region IPerformanceAdviserRule implementation
/// <summary>
/// Does some preliminary work before executing tests on elements. In this case,
/// we instantiate a list of FamilyInstances representing all doors that are flipped.
/// </summary>
/// <param name="document">The document being checked</param>
public void InitCheck(Autodesk.Revit.DB.Document document)
{
if (m_FlippedDoors == null)
m_FlippedDoors = new List<Autodesk.Revit.DB.ElementId>();
else
m_FlippedDoors.Clear();
return;
}
/// <summary>
/// This method does most of the work of the IPerformanceAdviserRule implementation.
/// It is called by PerformanceAdviser.
/// It examines the element passed to it (which was previously filtered by the filter
/// returned by GetElementFilter() (see below)). After checking to make sure that the
/// element is an instance, it checks the FacingFlipped property of the element.
///
/// If it is flipped, it adds the instance to a list to be used later.
/// </summary>
/// <param name="document">The active document</param>
/// <param name="element">The current element being checked</param>
public void ExecuteElementCheck(Autodesk.Revit.DB.Document document, Autodesk.Revit.DB.Element element)
{
if ((element is Autodesk.Revit.DB.FamilyInstance))
{
Autodesk.Revit.DB.FamilyInstance doorCurrent = element as Autodesk.Revit.DB.FamilyInstance;
if (doorCurrent.FacingFlipped)
m_FlippedDoors.Add(doorCurrent.Id);
}
}
/// <summary>
/// This method is called by PerformanceAdviser after all elements in document
/// matching the ElementFilter from GetElementFilter() are checked by ExecuteElementCheck().
///
/// This method checks to see if there are any elements (door instances, in this case) in the
/// m_FlippedDoor instance member. If there are, it iterates through that list and displays
/// the instance name and door tag of each item.
/// </summary>
/// <param name="document">The active document</param>
public void FinalizeCheck(Autodesk.Revit.DB.Document document)
{
if (m_FlippedDoors.Count == 0)
System.Diagnostics.Debug.WriteLine("No doors were flipped. Test passed.");
else
{
//Pass the element IDs of the flipped doors to the revit failure reporting APIs.
Autodesk.Revit.DB.FailureMessage fm = new Autodesk.Revit.DB.FailureMessage(m_doorWarningId);
fm.SetFailingElements(m_FlippedDoors);
Autodesk.Revit.DB.Transaction failureReportingTransaction = new Autodesk.Revit.DB.Transaction(document, "Failure reporting transaction");
failureReportingTransaction.Start();
document.PostFailure(fm);
failureReportingTransaction.Commit();
m_FlippedDoors.Clear();
}
}
/// <summary>
/// Gets the description of the rule
/// </summary>
/// <returns>The rule description</returns>
public string GetDescription()
{
return m_description;
}
/// <summary>
/// This method supplies an element filter to reduce the number of elements that PerformanceAdviser
/// will pass to GetElementCheck(). In this case, we are filtering for door elements.
/// </summary>
/// <param name="document">The document being checked</param>
/// <returns>A door element filter</returns>
public Autodesk.Revit.DB.ElementFilter GetElementFilter(Autodesk.Revit.DB.Document document)
{
return new Autodesk.Revit.DB.ElementCategoryFilter(Autodesk.Revit.DB.BuiltInCategory.OST_Doors);
}
/// <summary>
/// Gets the name of the rule
/// </summary>
/// <returns>The rule name</returns>
public string GetName()
{
return m_name;
}
/// <summary>
/// Returns true if this rule will iterate through elements and check them, false otherwise
/// </summary>
/// <returns>True</returns>
public bool WillCheckElements()
{
return true;
}
#endregion
}
**Parent page:** [Advanced Topics](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_html.html)

View File

@@ -0,0 +1,7 @@
# City
# City
City is an object that contains geographical location information for a known city in the world. It contains longitude, latitude, and time zone information. The city list is retrieved by the Cities property in the Application object. New cities cannot be added to the existing list in Revit. The city where the current project is located is not exposed by the Revit Platform API.
**Parent page:** [Place and Locations](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Place_and_Locations_html.html)

View File

@@ -0,0 +1,47 @@
# Place
# Place
## SiteLocation
In the Revit Platform API, the SiteLocation class contains place information including Latitude, Longitude, and Time Zone. This information identifies where the project is located in the world. When setting either the Latitude or Longitude, note that:
1. Revit will attempt to match the coordinates to a city it knows about, and if a match is found, will set the name accordingly.
2. Revit will attempt to automatically adjust the time zone value to match the new Longitude or Latitude value set using SunAndShadowSettings.CalculateTimeZone(). For some boundary cases, the time zone calculated may not be correct and the TimeZone property can be set directly if necessary.
Properties include information about the longitude, latitude, place name, and time zone. Its methods are:
* ConvertFromProjectTime - Converts project time to UTC time
* ConvertToProjectTime - Converts local time or UTC time to project time
* IsCompatibleWith - Checks whether the geographic coordinate system of this site is compatible with the given site
* SiteLocation.SetGeoCoordinateSystem(string coordSystem) - sets the Geo coordinate system for the current document
## InternalOrigin
The InternalOrigin class represents the origin of Revit's internal coordinate system. Each Revit project contains one InternalOrigin. It has the following members:
* InternalOrigin.Get(Document doc) - Returns the internal origin of the project
* InternalOrigin.Position - Read-only property which returns the XYZ value of the internal coordinates. The position will always be (0,0,0)
* InternalOrigin.SharedPosition - Read-only property which returns the shared position of the internal origin based on the active ProjectLocation of its project
## BasePoint
The BasePoint class represents the Project Base Point and Survey Point. Each Revit project contains one project base point and one survey point. The project base point represents the origin of the project coordinate system. The survey point represents the origin of the shared coordinate system.
* BasePoint.Position - Gets the XYZ value corresponding to the base point's position in Revit's internal coordinates
* BasePoint.SharedPosition - Gets the XYZ value corresponding to the base point's position in the transformed (shared) coordinates
* BasePoint.GetProjectBasePoint() - Gets the project base point
* BasePoint.GetSurveyPoint() - Gets the survey point
* BasePoint.Clipped gets and sets the clipped state of the survey point BasePoint based on the active ProjectLocation of its Document. For the project base point, it will always return false and attempting to set it will throw an exception.
**Figure 123: Project Place**
**Parent page:** [Place and Locations](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Place_and_Locations_html.html)

View File

@@ -0,0 +1,9 @@
# ProjectLocation
# ProjectLocation
A project only has one site which is the absolute location on the earth. However, it can have different locations relative to the projects around it. Depending on the coordinates and origins in use, there can be many ProjectLocation objects in one project.
By default each Revit project contains at least one named location, Internal. It is the active project location. You can retrieve it using the Document.ActiveProjectLocation property. All existing ProjectLocation objects are retrieved using the Document.ProjectLocations property.
**Parent page:** [Place and Locations](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Place_and_Locations_html.html)

View File

@@ -0,0 +1,122 @@
# Project Position
# Project Position
Project position is an object that represents a geographical offset and rotation. It is usually used by the ProjectLocation object to get and set geographical information. The following figure shows the results after changing the ProjectLocation geographical rotation and the coordinates for the same point. However, you cannot see the result of changing the ProjectLocation geographical offset directly.
**Figure 125: Point coordinates**
Note: East indicates that the Location is rotated counterclockwise; West indicates that the location is rotated clockwise. If the Angle value is between 180 and 360 degrees, Revit transforms it automatically. For example, if you select East and type 200 degrees for Angle, Revit transforms it to West 160 degrees.
**Figure 126: Geographical offset and rotation sketch map**
The following sample code illustrates how to retrieve the ProjectLocation object.
**Code Region 21-1: Retrieving the ProjectLocation object**
---
public void ShowActiveProjectLocationUsage(Autodesk.Revit.DB.Document document)
{
// Get the project location handle
ProjectLocation projectLocation = document.ActiveProjectLocation;
// Show the information of current project location
XYZ origin = new XYZ(0, 0, 0);
ProjectPosition position = projectLocation.GetProjectPosition(origin);
if (null == position)
{
throw new Exception("No project position in origin point.");
}
// Format the prompt string to show the message.
String prompt = "Current project location information:\n";
prompt += "\n\t" + "Origin point position:";
prompt += "\n\t\t" + "Angle: " + position.Angle;
prompt += "\n\t\t" + "East to West offset: " + position.EastWest;
prompt += "\n\t\t" + "Elevation: " + position.Elevation;
prompt += "\n\t\t" + "North to South offset: " + position.NorthSouth;
// Angles are in radians when coming from Revit API, so we
// convert to degrees for display
const double angleRatio = Math.PI / 180; // angle conversion factor
SiteLocation site = projectLocation.GetSiteLocation();
string degreeSymbol = ((char)176).ToString();
prompt += "\n\t" + "Site location:";
prompt += "\n\t\t" + "Latitude: " + site.Latitude / angleRatio + degreeSymbol;
prompt += "\n\t\t" + "Longitude: " + site.Longitude / angleRatio + degreeSymbol;
prompt += "\n\t\t" + "TimeZone: " + site.TimeZone;
TaskDialog.Show("Revit", prompt);
}
Note: There is only one active project location at a time. To see the result after changing the ProjectLocation geographical offset and rotation, change the Orientation property from Project North to True North in the plan view Properties pane.
**Figure 128: Project is rotated 30 degrees from Project North to True North**
**Figure 129: Project location information**
### Creating and Deleting Project Locations
Create new project locations by duplicating an existing project location using the Duplicate() method. The following code sample illustrates how to create a new project location using the Duplicate() method.
**Code Region 21-2: Creating a project location**
---
public ProjectLocation DuplicateLocation(Autodesk.Revit.DB.Document document, string newName)
{
ProjectLocation currentLocation = document.ActiveProjectLocation;
ProjectLocationSet locations = document.ProjectLocations;
foreach (ProjectLocation projectLocation in locations)
{
if (projectLocation.Name == newName)
{
throw new Exception("The name is same as a project location's name, please change one.");
}
}
return currentLocation.Duplicate(newName);
}
The following code sample illustrates how to delete an existing project location from the current project.
**Code Region 21-3: Deleting a project location**
---
public void DeleteLocation(Autodesk.Revit.DB.Document document)
{
ProjectLocation currentLocation = document.ActiveProjectLocation;
//There must be at least one project location in the project.
ProjectLocationSet locations = document.ProjectLocations;
if (1 == locations.Size)
{
return;
}
string name = "location";
if (name != currentLocation.Name)
{
foreach (ProjectLocation projectLocation in locations)
{
if (projectLocation.Name == name)
{
ICollection<Autodesk.Revit.DB.ElementId> elemSet = document.Delete(projectLocation.Id);
if (elemSet.Count > 0)
{
TaskDialog.Show("Revit","Project Location Deleted!");
}
}
}
}
}
Note: The following rules apply to deleting a project location:
* The active project location cannot be deleted because there must be at least one project location in the project.
* You cannot delete the project location if the ProjectLocationSet class instance is read-only.
**Parent page:** [Place and Locations](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Place_and_Locations_html.html)

View File

@@ -0,0 +1,18 @@
# Place and Locations
# Place and Locations
Every building has a unique place in the world because the Latitude and Longitude are unique. In addition, a building can have many locations in relation to other buildings. The Revit Platform API Site namespace uses certain classes to save the geographical location information for Revit projects.
Note: The Revit Platform API does not expose the Site menu functions. Only Site namespace provides functions corresponding to the Location options found on the Project Location panel on the Manage tab.
**Pages in this section**
* [Place](Place_and_Locations/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Place_and_Locations_Place_html.html)
* [City](Place_and_Locations/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Place_and_Locations_City_html.html)
* [ProjectLocation](Place_and_Locations/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Place_and_Locations_ProjectLocation_html.html)
* [Project Position](Place_and_Locations/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Place_and_Locations_Project_Position_html.html)
**Parent page:** [Advanced Topics](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_html.html)

View File

@@ -0,0 +1,182 @@
# Point Cloud Client
# Point Cloud Client
The point cloud client API supports read and modification of point cloud instances within Revit.
The points supplied by the point cloud instances come from the point cloud engine, which is either a built-in engine within Revit, or [a third party engine loaded as an application](./Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Point_Clouds_Point_Cloud_Engine_html.html). A client point cloud API application doesnt need to be concerned with the details of how the engine stores and serves points to Revit. Instead, the client API can be used to create point clouds, manipulate their properties, and read the points found matching a given filter.
The main classes related to point clouds are:
* **PointCloudType** \- type of point cloud loaded into a Revit document. Each PointCloudType maps to a single file or identifier (depending upon the type of Point Cloud Engine which governs it).
* **PointCloudInstance** \- an instance of a point cloud in a location in the Revit project.
* **PointCloudFilter** \- a filter determining the volume of interest when extracting points.
* **PointCollection** \- a collection of points obtained from an instance and a filter.
* **PointIterator** \- an iterator for the points in a PointCollection.
* **CloudPoint** \- an individual point cloud point, representing an X, Y, Z location in the coordinates of the cloud, and a color.
* **PointCloudOverrides** \- and its related settings classes specify graphic overrides that are stored by a view to be applied to a PointCloudInstance element, or a scan within the element.
### Point cloud file paths
Two important path locations dealing with point clouds are available as read-only data:
1. PointCloudType.GetPath() - The path of the link source from which the points are loaded.
2. Application.PointCloudsRootPath - The root path for point cloud files which is used by Revit to calculate relative paths to point cloud files.
### Creating a Point Cloud
To create a new point cloud in a Revit document, create a PointCloudType and then use it to create a PointCloudInstance. The static PointCloudType.Create() method requires the engine identifier, as it was registered with Revit by a third party, or the file extension of the point cloud file, if it is a supported file type. It also requires a file name or the identification string for a non-file based engine. In the following sample, a pcg file is used to create a point cloud in a Revit document.
**Code Region: Create a point cloud from an rcs file**
---
private PointCloudInstance CreatePointCloud(Document doc)
{
PointCloudType type = PointCloudType.Create(doc, "rcs", "c:\\32_cafeteria.rcs");
return (PointCloudInstance.Create(doc, type.Id, Transform.Identity));
}
**Figure: Point Cloud from 32_cafeteria.rcs**
### Accessing Points in a Point Cloud
There are two ways to access the points in a point cloud:
1. Iterate the resulting points directly from the PointCollection return using the `IEnumerable<CloudPoint>` interface.
2. Get a pointer to the point storage of the collection and access the points directly in memory in an unsafe interface.
Either way, the first step to access a collection of points from the PointCloudInstance is to use the method
* PointCloudInstance.GetPoints(PointCloudFilter filter, double averageDistance, int numPoints)
Note that as a result of search algorithms used by Revit and the point cloud engine, the exact requested number of points may not be returned.
Although the second option involves dealing with pointers directly, there may be performance improvements when traversing large buffers of points. However, this option is only possible from C# and C++/CLI.
The following two examples show how to iterate part of a point cloud using on one of these two methods.
**Code Region: Reading point cloud points by iteration**
---
private void GetPointCloudDataByIteration(PointCloudInstance pcInstance, PointCloudFilter pointCloudFilter)
{
// read points by iteration
double averageDistance = 0.001;
PointCollection points = pcInstance.GetPoints(pointCloudFilter, averageDistance, 10000); // Get points. Number of points is determined by the needs of the client
foreach (CloudPoint point in points)
{
// Process each point
System.Drawing.Color color = System.Drawing.ColorTranslator.FromWin32(point.Color);
String pointDescription = String.Format("({0}, {1}, {2}, {3}", point.X, point.Y, point.Z, color.ToString());
}
}
**Code Region: Reading point cloud points by pointer**
---
public unsafe void GetPointCloudDataByPointer(PointCloudInstance pcInstance, PointCloudFilter pointCloudFilter)
{
double averageDistance = 0.001;
PointCollection points = pcInstance.GetPoints(pointCloudFilter, averageDistance, 10000);
CloudPoint* pointBuffer = (CloudPoint*)points.GetPointBufferPointer().ToPointer();
int totalCount = points.Count;
for (int numberOfPoints = 0; numberOfPoints < totalCount; numberOfPoints++)
{
CloudPoint point = *(pointBuffer + numberOfPoints);
// Process each point
System.Drawing.Color color = System.Drawing.ColorTranslator.FromWin32(point.Color);
String pointDescription = String.Format("({0}, {1}, {2}, {3}", point.X, point.Y, point.Z, color.ToString());
}
}
### Filters
Filters are used both to limit the volume which is searched when reading points, and also to govern the display of point clouds. A PointCloudFilter can be created based upon a collection of planar boundaries. The filter will check whether a point is located on the “positive” side of each input plane, as indicated by the positive direction of the plane normal. Therefore, such filter implicitly defines a volume, which is the intersection of the positive half-spaces corresponding to all the planes. This volume does not have to be closed, but it will always be convex.
The display of point clouds can be controlled by assigning a filter to:
* PointCloudInstance.SetSelectionFilter()
Display of the filtered points will be based on the value of the property:
* PointCloudInstance.FilterAction
If it is set to None, the selection filter is ignored. If it is set to Highlight, points that pass the filter are highlighted. If it is set to Isolate, only points that pass the filter will be visible.
The following example will highlight a subset of the points in a point cloud based on its bounding box.
**Code Region: Reading point cloud points by pointer**
---
public PointCloudFilter ReadPointCloud(PointCloudInstance pointCloudInstance)
{
// Filter will match 1/8 of the overall point cloud
// Use the bounding box (filter coordinates are in the coordinates of the model)
BoundingBoxXYZ boundingBox = pointCloudInstance.get_BoundingBox(null);
List<Plane> planes = new List<Plane>();
XYZ midpoint = (boundingBox.Min + boundingBox.Max) / 2.0;
// X boundaries
planes.Add(Plane.CreateByNormalAndOrigin(XYZ.BasisX, boundingBox.Min));
planes.Add(Plane.CreateByNormalAndOrigin(-XYZ.BasisX, midpoint));
// Y boundaries
planes.Add(Plane.CreateByNormalAndOrigin(XYZ.BasisY, boundingBox.Min));
planes.Add(Plane.CreateByNormalAndOrigin(-XYZ.BasisY, midpoint));
// Z boundaries
planes.Add(Plane.CreateByNormalAndOrigin(XYZ.BasisZ, boundingBox.Min));
planes.Add(Plane.CreateByNormalAndOrigin(-XYZ.BasisZ, midpoint));
// Create filter
PointCloudFilter filter = PointCloudFilterFactory.CreateMultiPlaneFilter(planes);
pointCloudInstance.FilterAction = SelectionFilterAction.Highlight;
return filter;
}
This is the result when the sample above is run on a small pipe point cloud:
**Figure: Point cloud with selection filter**
The Selection.PickBox() method which invokes a general purpose two-click editor that lets the user to specify a rectangular area on the screen can be used in conjunction with a PointCloudFilter by using the resulting PickedBox to generate the planar boundaries of the filter.
### Scans
An .rcp file can contain multiple scans. The method PointCloudInstance.GetScans() returns a list of scan names which can be used to set visibility and fixed color overrides independently for each scan in the PointCloudInstance. PointCloudInstance.ContainsScan() indicates whether the given scan name is contained in the point cloud instance while PointCloudInstance.GetScanOrigin() will return the origin of the given scan in model coordinates.
### Regions
Scan regions are specific to Autodesk ReCap™. If a point cloud was created in ReCap, it may have regions. PointCloudInstance.GetRegions() returns a list of region names which can be used to set visibility and fixed color overrides independently for each region in the PointCloudInstance.
`PointCloudType.GetReCapProject()` provides a direct entry point to get access to an object from the ReCap SDK (`ReCapWrapper.RCProject`) from Revit. This object represents the point cloud from the RC file path stored in `PointCloudType`. The ReCap assembly ReCapWrapper.dll will need to be included into code using this method. The coordinate system in RCProject is defined by the Point Cloud. Please refer to ReCap SDK documentation for `RCProject.getCoordinateSystem()`. If you need points converted to the modeling coordinate system in Revit, you can obtain the transformation matrix from `PointCloudInstance.GetTransform()`.
### Overrides
Point cloud override settings assigned to a given view can be modified using the Revit API. These settings correspond to the settings on the Point Clouds tab of the Visibility/Graphics Overrides task pane in the Revit UI. Overrides can be applied to an entire point cloud instance, or to specific scans within that instance. Options for the overrides include setting visibility for scans in the point cloud instance, setting it to a fixed color, or to color gradients based on elevation, normals, or intensity. The property PointCloudInstance.SupportsOverrides identifies point clouds which support override settings (clouds which are based on .rcp or .rcs files).
The following classes are involved in setting the overrides for point clouds:
* **PointCloudOverrides** \- Used to get or set the PointCloudOverrideSettings for a PointCloudInstance, one of its scans, or for a particular region within the PointCloudInstance.
* **PointCloudOverrideSettings** \- Used to get or set the visibility, color mode, and PointCloudColorSettings.
* **PointCloudColorSettings** \- Used to assign specific colors for certain color modes to a PointCloudInstance element, or one of its scans. Does not apply if the PointCloudColorMode is NoOverride or Normals.
**Parent page:** [Point Clouds](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Point_Clouds_html.html)

View File

@@ -0,0 +1,28 @@
# Point Cloud Engine
# Point Cloud Engine
A custom point cloud engine can be implemented to supply cloud points to Revit.
A point cloud engine can be file-based or non-file-based. A file-based implementation requires that each point cloud be mapped to a single file on disk. Revit will allow users to create new point cloud instances in a document directly by selecting point cloud files whose extension matches the engine identifier. These files are treated as external links in Revit and may be reloaded and remapped when necessary from the Manage Links dialog.
A non-file-based engine implementation may obtain point clouds from anywhere (e.g., from a database, from a server, or from one part of a larger aggregate file). Because there is no file that the user may select, Revit's user interface will not allow a user to create a point cloud of this type. Instead, the engine provider supplies a custom command using PointCloudType.Create() and PointCloudInstance.Create() to create and place point clouds of this type. The Manage Links dialog will show the point clouds of this type, but since there is no file associated with the point cloud, the user cannot manage, reload or remap point clouds of this type.
Regardless of the type of implementation, a custom engine implementation consists of the following:
* An implementation of IPointCloudEngine registered with Revit via the PointCloudEngineRegistry.
* An implementation of IPointCloudAccess which will respond to inquiries from Revit regarding the properties of a single point cloud.
* An implementation of IPointSetIterator which will return sets of points to Revit when requested.
In order to supply the points of the point cloud to Revit, there are two ReadPoints() methods which must be implemented:
* IPointCloudAccess.ReadPoints() - this provides a single set of points in a one-time call, either from Revit or the API. Revit uses this during some display activities including selection pre-highlighting. It is also possible for API clients to call this method directly via PointCloudInstance.GetPoints().
* IPointSetIterator.ReadPoints() - this provides a subset of points as a part of a larger iteration of points in the cloud. Revit uses this method during normal display of the point cloud; quantities of points will be requested repeatedly until it obtains enough points or until something in the display changes. The engine implementation must keep track of which points have been returned to Revit during any given point set iteration.
See the PointCloudEngine folder under the Samples directory included with the Revit API SDK for a complete example of registering and implementing both file-based and non-file-based point cloud engines.
**Parent page:** [Point Clouds](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Point_Clouds_html.html)

View File

@@ -0,0 +1,27 @@
# Point Clouds
# Point Clouds
The Revit API provides 2 ways to work with point clouds. The first way allows you to create new point cloud instances, read and filter points, select sub-sets of the overall points, and select points to be highlighted or isolated. The second way allows you to use your own point cloud engine and process unsupported file formats (i.e. other than .pcg, .rcp or .rcs), providing points to Revit for the user to see.
* Client API
* Create new Point Cloud instances
* Read & Filter Points
* Point Set Selection
* Control Point Cloud highlighting
* Engine API
* Register Point Cloud file extension
* Provide points to Revit for rendering
**Pages in this section**
* [Point Cloud Client](Point_Clouds/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Point_Clouds_Point_Cloud_Client_html.html)
* [Point Cloud Engine](Point_Clouds/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Point_Clouds_Point_Cloud_Engine_html.html)
**Parent page:** [Advanced Topics](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_html.html)

View File

@@ -0,0 +1,120 @@
# Extensible Storage
# Extensible Storage
Create your own class-like Schema data structures and attach instances of them to any Element in a Revit model.
Schema-based data is saved with the Revit model and allows for higher-level, metadata-enhanced, object-oriented data structures. Schema data can be configured to be readable and/or writable to all users, just a specific application vendor, or just a specific application from a vendor.
The following steps are necessary to store data with Elements in Revit:
1. Create and name a new schema.
2. Set the read/write access for the schema.
3. Define one or more fields of data for the schema.
4. Create an entity based on the schema.
5. Assign values to the fields for the entity.
6. Associate the entity with a Revit element.
### Schemas and SchemaBuilder
The first step to creating extensible storage is to define the schema. A schema is similar to a class in an object-oriented programming language. Use the SchemaBuilder class constructor to create a new schema. SchemaBuilder is a helper class used to create schemas. Once a schema is finalized using SchemaBuilder, the Schema class is used to access properties of the schema. At that stage, the schema is no longer editable.
Although the SchemaBuilder constructor takes a GUID which is used to identify the schema, a schema name is also required. After creating the schema, call SchemaBuilder.SetSchemaName() to assign a user-friendly identifier for the schema. The schema name is useful to identify a schema in an error message.
The read and write access levels of entities associated with the schema can be set independently. The options are Public, Vendor, or Application. If either the read or write access level is set to Vendor, the VendorId of the third-party vendor that may access entities of the schema must be specified. If either access level is set to Application, the GUID of the application or add-in that may access entities of the schema must be supplied.
Note: Schemas are stored with the document and any Revit API add-in may read the available schemas in the document, as well as some data of the schema. However, access to the fields of a schema is restricted based on the read access defined in the schema and the actual data in the entities stored with specific elements is restricted based on the read and write access levels set in the schema when it is defined.
### Fields and FieldBuilder
Once the schema has been created, fields may be defined. A field is similar to a property of a class. It contains a name, documentation, value type and unit type. Fields can be a simple type, an array, or a map. The following simple data types are allowed:
**Type** | **Default Value**
---|---
int | 0
short | 0
byte | 0
double | 0.0
float | 0.0
bool | false
string | Empty string ("")
GUID | Guid.Empty {00000000-0000-0000-0000-000000000000}
ElementId | ElementId.InvalidElementId
Autodesk.Revit.DB.XYZ | (0.0,0.0,0.0)
Autodesk.Revit.DB.UV | (0.0,0.0)
Additionally, a field may be of type Autodesk.Revit.DB.ExtensibleStorage.Entity. In other words, an instance of another Schema, also known as a SubSchema or SubEntity. The default value for a field of this type is Entity with null schema, and guid of Guid.Empty.
When using string fields, note that Revit has a 16mb limit on string objects.
A simple field can be created using the SchemaBuilder.AddSimpleField() method to specify a name and type for the field. AddSimpleField() returns a FieldBuilder, which is a helper class for defining Fields. If the type of the field was specified as Entity, use FieldBuilder.SetSubSchemaGUID() to specify the GUID of the schema of the Entities that are to be stored in this field.
Use the SchemaBuilder.AddArrayField() method to create a field containing an array of values in the Schema, with a given name and type of contained values. Array fields can have all the same types as simple fields.
Use the SchemaBuilder.AddMapField() method to create a field containing an ordered key-value map in the Schema, with given name, type of key and type of contained values. Supported types for values are the same as for simple fields. Supported types for keys are limited to int, short, byte, string, bool, ElementId and GUID.
Once the schema is finalized using SchemaBuilder, fields can no longer be edited using FieldBuilder. At that stage, the Schema class provides methods to get a Field by name, or a list of all Fields defined in the Schema.
### Entities
After all fields have been defined for the schema, SchemaBuilder.Finish() will return the finished Schema. A new Entity can be created using that schema. For each Field in the Schema, the value can be stored using Entity.Set(), which takes a Field and a value (whose type is dependent on the field type). Once all applicable fields have been set for the entity, it can be assigned to an element using the Element.SetEntity() method.
To retrieve the data later, call Element.GetEntity() passing in the corresponding Schema. If no entity based on that schema was saved with the Element, an invalid Entity will be returned. To check that a valid Entity was returned, call the Entity.IsValid() method. Field values from the entity can be obtained using the Entity.Get() method.
To remove an extensible storage entity from an Element, call Element.DeleteEntity() passing in the Schema that was used to create it.
To determine Entities stored with an element, use the Element.GetEntitySchemaGuids() method, which returns the Schema guids of any Entities for the Element. The Schema guids can be used with the static method Schema.Lookup() to retrieve the corresponding Schemas.
The following is an example of defining an extensible storage Schema, creating an Entity, setting its values, assigning it to an Element, and retrieving the data.
**Code Region 22-9: Extensible Storage**
---
// Create a data structure, attach it to a wall, populate it with data, and retrieve the data back from the wall
void StoreDataInWall(Wall wall, XYZ dataToStore)
{
Transaction createSchemaAndStoreData = new Transaction(wall.Document, "tCreateAndStore");
createSchemaAndStoreData.Start();
SchemaBuilder schemaBuilder =
new SchemaBuilder(new Guid("720080CB-DA99-40DC-9415-E53F280AA1F0"));
schemaBuilder.SetReadAccessLevel(AccessLevel.Public); // allow anyone to read the object
schemaBuilder.SetWriteAccessLevel(AccessLevel.Vendor); // restrict writing to this vendor only
schemaBuilder.SetVendorId("ADSK"); // required because of restricted write-access
schemaBuilder.SetSchemaName("WireSpliceLocation");
// create a field to store an XYZ
FieldBuilder fieldBuilder =
schemaBuilder.AddSimpleField("WireSpliceLocation", typeof(XYZ));
fieldBuilder.SetSpec(SpecTypeId.Length);
fieldBuilder.SetDocumentation("A stored location value representing a wiring splice in a wall.");
Schema schema = schemaBuilder.Finish(); // register the Schema object
Entity entity = new Entity(schema); // create an entity (object) for this schema (class)
// get the field from the schema
Field fieldSpliceLocation = schema.GetField("WireSpliceLocation");
// set the value for this entity
entity.Set<XYZ>(fieldSpliceLocation, dataToStore, UnitTypeId.Meters);
wall.SetEntity(entity); // store the entity in the element
// get the data back from the wall
Entity retrievedEntity = wall.GetEntity(schema);
XYZ retrievedData =
retrievedEntity.Get<XYZ>(schema.GetField("WireSpliceLocation"),
UnitTypeId.Meters);
createSchemaAndStoreData.Commit();
}
# Advantages
#### Self Documenting and Self-Defining
Creating a schema by adding fields, units, sub-entities, and description strings is not only a means for storing data. It is also implicit documentation for other users and a way for others to create entities of the same schema later with an easy adoption path.
#### Takes Advantage of Locality
Because schema entities are stored on a per-element basis, there is no need to necessarily read all extensible storage data in a document (e.g., all data from all beam family instances) when an application might only need data for the currently selected beam. This allows the potential for more specifically targeted data access code and better data access performance overall.
**Parent page:** [Storing Data in the Revit model](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Storing_Data_in_the_Revit_model_html.html)

View File

@@ -0,0 +1,17 @@
# Storing Data in the Revit model
# Storing Data in the Revit model
Use shared parameters or extensible storage to store data in the Revit model.
The Revit API provides two methods for storing data in the Revit model. The first is using shared parameters. The Revit API gives programmatic access to the same shared parameters feature that is available through the Revit UI. Shared parameters, if defined as visible, will be viewable to the user in an element's property window. Shared parameters can be assigned to many, but not all, categories of elements. For more information, see [Shared Parameters](../Basic_Interaction_with_Revit_Elements/Parameters/Revit_API_Revit_API_Developers_Guide_Basic_Interaction_with_Revit_Elements_Parameters_Shared_Parameters_html.html "Shared Parameters are parameter definitions stored in an external text file").
The other option is extensible storage, which allows you to create custom data structures and then assign instances of that data to elements in the model. This data is never visible to the user in the Revit UI, but may be accessible to other third party applications via the Revit API depending on the read/write access assigned to the schema when it is defined. Unlike Shared Parameters, extensible storage is not limited to certain categories of elements. Extensible storage data can be assigned to any object that derives from the base class Element in the Revit model.
**Pages in this section**
* [Extensible Storage](Storing_Data_in_the_Revit_model/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Storing_Data_in_the_Revit_model_Extensible_Storage_html.html)
**Parent page:** [Advanced Topics](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_html.html)

View File

@@ -0,0 +1,15 @@
# Transport Layer Security
# Transport Layer Security
When your add-on requires Internet communications and a specific security protocol is involved, if the protocol is TLS 1.0, 1.1 or 1.2 do not write any setting in the add-on. Instead take advantage of the native TLS support in Revit and its target .NET Framework. The complexities due to variety of Windows versions as well as .NET Framework versions have been handled in Revit.
If the add-on needs to specify a security protocol or its version, do not hard-code it exclusively, e.g., by directly assigning the protocol/version to the application-wide property `ServicePointManager.SecurityProtocol`. This will override Revit's native TLS configuration, which is critical for Revit to communicate with various Autodesk cloud services.
A **problematic** usage is `System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12;`.
Instead, specify the protocol/version inclusively, e.g., by using bitwise OR (logical OR) on the application-wide property ServicePointManager.SecurityProtocol.
A **correct** usage is `System.Net.ServicePointManager.SecurityProtocol |= System.Net.SecurityProtocolType.Tls12;`.
**Parent page:** [Advanced Topics](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_html.html)

View File

@@ -0,0 +1,14 @@
# Window Handle
# Window Handle
Two properties allow access to the handle of the Revit main window:
* Autodesk.Revit.UI.UIApplication.MainWindowHandle
* Autodesk.Revit.UI.UIControlledApplication.MainWindowHandle
This handle should be used when displaying modal dialogs and message windows to insure that they are properly parented. Use these properties instead of System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle, which is not a reliable method for retrieving the main window handle.
**Parent page:** [Advanced Topics](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_html.html)

View File

@@ -0,0 +1,117 @@
# Editing Elements in Worksets
# Editing Elements in Worksets
## Overview
Users working in teams can encounter usability issues with Revit API add-ins beyond what a single user might experience. In particular, how an add-in is designed can prevent or create editing conflicts. For example, if an add-in attempts to edit thousands of elements, all of those elements will need to be checked out to the local user and will be unavailable to other users until a synchronize with central is performed. Or some of the elements may be checked out to other users and unavailable to be edited. This is important to keep in mind when making changes to a workshared model from the API.
The basic model editing workflow goes like this:
Action | Example | Why this is important
---|---|---
The user changes some elements in the model | User drags a wall | These changes are "user changes". The user must borrow these elements to make the change.
Revit regenerates additional data in the model as needed | Joined walls move, floor updates, roof updates, room updates, room tags check if they're still in their rooms | These changes are "system changes". Even though they are changed, they are still available to other users.
Most API changes are "user changes" and are treated the same as if the local user made the changes manually. This is the case whether called from an External Command, a macro, or an event. The one exception is that changes made from updaters are treated as system changes. .
## Element Ownership
One way to address worksharing issues that may arise from attempting to edit an element in a workshared document is to set up FailureHandlingOptions for the transaction used to edit the element. This allows for catching and suppressing editing errors automatically and rollback the changes as shown below:
**Code Region: Suppressing worksharing errors**
---
public static void TryToEditGeometricElement(Element elem, bool useFailureHandlingOpts)
{
Document doc = elem.Document;
using (Transaction t = MakeTransaction(doc, "Move element", useFailureHandlingOpts))
{
t.Start();
ElementTransformUtils.MoveElement(doc, elem.Id, new XYZ(1, 1, 0));
t.Commit();
}
}
private static Transaction MakeTransaction(Document doc, string name, bool useFailureHandlingOpts)
{
Transaction t = new Transaction(doc, name);
if (useFailureHandlingOpts)
{
FailureHandlingOptions opts = t.GetFailureHandlingOptions();
opts.SetClearAfterRollback(true);
opts.SetFailuresPreprocessor(new WorksharingErrorsPreprocessor());
t.SetFailureHandlingOptions(opts);
}
return t;
}
private class WorksharingErrorsPreprocessor : IFailuresPreprocessor
{
FailureProcessingResult IFailuresPreprocessor.PreprocessFailures(FailuresAccessor failuresAccessor)
{
return FailureProcessingResult.Continue;
}
}
The WorksharingUtils class can be used to modify element and workset ownership. The CheckoutElements() method obtains ownership for the current user of as many specified elements as possible, while the CheckoutWorksets() method does the same for worksets. These methods are useful for attempting to checkout elements prior to performing edits. Editing is limited to elements and worksets the user owns until Reload Latest or Synchronize with Central is conducted after the model is opened. The RelinquishOwnership() method relinquishes elements and worksets owned by the current user based on the specified RelinquishOptions.
For best performance, checkout all elements or worksets and relinquish items in one big call, rather than many small calls. However, when working on a cloud model and checking out a large number of elements in one request `CheckoutElementsRequestTooLargeException` may be thrown. Checking out corresponding worksets is recommended in this case.
Note: When checking out an element, Revit may check out additional elements that are needed to make the requested element editable. For example, if an element is in a group, Revit will checkout the entire group. The following example tries to checkout the given element prior to editing and issues a message to the user if there is an issue.
**Code Region: Checkout elements**
---
public static bool AttemptToCheckoutInAdvance(Element element)
{
Document doc = element.Document;
String categoryName = element.Category.Name;
// Checkout attempt
ICollection<ElementId> checkedOutIds = WorksharingUtils.CheckoutElements(doc, new ElementId[] { element.Id });
// Confirm checkout
bool checkedOutSuccessfully = checkedOutIds.Contains(element.Id);
if (!checkedOutSuccessfully)
{
TaskDialog.Show("Element is not checked out", "Cannot edit the " + categoryName + " element - " +
"it was not checked out successfully and may be checked out to another.");
return false;
}
// If element is updated in central or deleted in central, it is not editable
ModelUpdatesStatus updatesStatus = WorksharingUtils.GetModelUpdatesStatus(doc, element.Id);
if (updatesStatus == ModelUpdatesStatus.DeletedInCentral || updatesStatus == ModelUpdatesStatus.UpdatedInCentral)
{
TaskDialog.Show("Element is not up to date", "Cannot edit the " + categoryName + " element - " +
"it is not up to date with central, but it is checked out.");
return false;
}
return true;
}
The next example demonstrates checking out all the view worksets.
**Code Region: Checkout worksets**
---
void CheckoutAllViewWorksets(Document doc)
{
FilteredWorksetCollector collector = new FilteredWorksetCollector(doc);
// find all view worksets
collector.OfKind(WorksetKind.ViewWorkset);
ICollection<WorksetId> viewworksets = collector.ToWorksetIds();
ICollection<WorksetId> checkoutworksets = WorksharingUtils.CheckoutWorksets(doc, viewworksets);
TaskDialog.Show("Checked out worksets", "Number of worksets checked out: " + checkoutworksets.Count);
}
**Parent page:** [Worksharing](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Worksharing_html.html)

View File

@@ -0,0 +1,126 @@
# Elements in Worksets
# Elements in Worksets
Each element in the document must belong to one and only one workset. Each element has a WorksetId which identifies the unique workset to which it belongs. Additionally, given a WorksetId, it is possible to get all of the elements in the document belonging to that Workset using the ElementWorksetFilter as shown below.
**Code Region: ElementWorksetFilter**
---
public void WorksetElements(Document doc, Workset workset)
{
// filter all elements that belong to the given workset
FilteredElementCollector elementCollector = new FilteredElementCollector(doc);
ElementWorksetFilter elementWorksetFilter = new ElementWorksetFilter(workset.Id, false);
ICollection<Element> worksetElemsfounds = elementCollector.WherePasses(elementWorksetFilter).ToElements();
// how many elements were found?
int elementsCount = worksetElemsfounds.Count;
String message = "Element count : " + elementsCount;
// Get name and/or Id of the elements that pass the given filter and show a few of them
int count = 5; // show info for 5 elements only
foreach (Element ele in worksetElemsfounds)
{
if (null != ele)
{
message += "\nElementId : " + ele.Id;
message += ", Element Name : " + ele.Name;
if (0 == --count)
break;
}
}
Autodesk.Revit.UI.TaskDialog.Show("ElementsOfWorkset", message);
}
New elements are automatically placed in the active workset in the user's local copy of the model. Since the WorksetId for an element is a read only property, use the parameter ELEM_PARTITION_PARAM. The following example demonstrates the creation of an element that is changed to belong to a different workset.
**Code Region: Changing a new element's workset**
---
public void ChangeWorkset(Document doc)
{
String targetWorksetName = "Target workset";
//Find target workset
FilteredWorksetCollector worksetCollector = new FilteredWorksetCollector(doc);
worksetCollector.OfKind(WorksetKind.UserWorkset);
Workset workset = worksetCollector.FirstOrDefault<Workset>(ws => ws.Name == targetWorksetName);
// Workset not found, abort
if (workset == null)
{
TaskDialog dialog = new TaskDialog("Error");
dialog.MainInstruction = String.Format("There is no workset named {0} in the document. Aborting this operation.", targetWorksetName);
dialog.MainIcon = TaskDialogIcon.TaskDialogIconWarning;
dialog.Show();
return;
}
// Find "Level 1" for the new wall
FilteredElementCollector collector = new FilteredElementCollector(doc);
collector.OfClass(typeof(Level));
Level level = collector.Cast<Level>().First<Level>(lvl => lvl.Name == "Level 1");
using (Transaction t = new Transaction(doc, "Add elements by API"))
{
t.Start();
// Create the wall
Wall wall = Wall.Create(doc, Line.CreateBound(new XYZ(25, 0, 0), new XYZ(25, 15, 0)), level.Id, false);
// Get the parameter that stores the workset id
Parameter p = wall.GetParameter(ParameterTypeId.ElemPartitionParam);
// This parameter storage type is Integer
p.Set(workset.Id.IntegerValue);
t.Commit();
}
}
Worksharing information such as the current owner and checkout status of an element can be obtained using the WorksharingUtils class. It is a static class that contains utility functions related to worksharing.
**Code Region: WorksharingUtils**
---
public void GetElementWorksharingInfo(Document doc, ElementId elemId)
{
String message = String.Empty;
message += "Element Id: " + elemId;
Element elem = doc.GetElement(elemId);
if(null == elem)
{
message += "Element does not exist";
return;
}
// The workset the element belongs to
WorksetId worksetId = elem.WorksetId;
message += ("\nWorkset Id : " + worksetId.ToString());
// Model Updates Status of the element
ModelUpdatesStatus updateStatus = WorksharingUtils.GetModelUpdatesStatus(doc, elemId);
message += ("\nUpdate status : " + updateStatus.ToString());
// Checkout Status of the element
CheckoutStatus checkoutStatus = WorksharingUtils.GetCheckoutStatus(doc, elemId);
message += ("\nCheckout status : " + checkoutStatus.ToString());
// Getting WorksharingTooltipInfo of a given element Id
WorksharingTooltipInfo tooltipInfo = WorksharingUtils.GetWorksharingTooltipInfo(doc, elemId);
message += ("\nCreator : " + tooltipInfo.Creator);
message += ("\nCurrent Owner : " + tooltipInfo.Owner);
message += ("\nLast Changed by : " + tooltipInfo.LastChangedBy);
Autodesk.Revit.UI.TaskDialog.Show("GetElementWorksharingInfo", message);
}
**Parent page:** [Worksharing](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Worksharing_html.html)

View File

@@ -0,0 +1,316 @@
# Opening a Workshared Document
# Opening a Workshared Document
The Application.OpenDocumentFile(ModelPath, OpenOptions) method can be used to set options related to opening a workshared document. In addition to options to detach from the central document or to allow a local file to be opened ReadOnly by a user other than its owner, options may also be set related to worksets. When a workshared document is opened, all system worksets are automatically opened, however user-created worksets can be specified to be opened or closed. Elements in an open workset can be expanded and displayed. However, elements in a closed workset are not displayed to avoid expanding them. By only opening worksets necessary in the current session, Revit's memory footprint is reduced, which can help with performance.
In the example below, a document is opened with two worksets specified to be opened. Note that the WorksharingUtils.GetUserWorksetInfo() method can be used to access workset information from a closed Revit document.
**Code Region: Open Workshared Document**
---
Document OpenDocumentWithWorksets(Application app, ModelPath projectPath)
{
Document doc = null;
try
{
// Get info on all the user worksets in the project prior to opening
IList<WorksetPreview> worksets = WorksharingUtils.GetUserWorksetInfo(projectPath);
IList<WorksetId> worksetIds = new List<WorksetId>();
// Find two predetermined worksets
foreach (WorksetPreview worksetPrev in worksets)
{
if (worksetPrev.Name.CompareTo("Workset1") == 0 ||
worksetPrev.Name.CompareTo("Workset2") == 0)
{
worksetIds.Add(worksetPrev.Id);
}
}
OpenOptions openOptions = new OpenOptions();
// Setup config to close all worksets by default
WorksetConfiguration openConfig = new WorksetConfiguration(WorksetConfigurationOption.CloseAllWorksets);
// Set list of worksets for opening
openConfig.Open(worksetIds);
openOptions.SetOpenWorksetsConfiguration(openConfig);
doc = app.OpenDocumentFile(projectPath, openOptions);
}
catch (Exception e)
{
TaskDialog.Show("Open File Failed", e.Message);
}
return doc;
}
Another option is to open the document while just opening the last viewed worksets.
**Code Region: Open last viewed worksets**
---
public static Document OpenLastViewed(UIApplication uiApplication)
{
Application application = uiApplication.Application;
// Setup options
OpenOptions options1 = new OpenOptions();
// Default config opens all. Close all first, then open last viewed to get the correct settings.
WorksetConfiguration worksetConfig = new WorksetConfiguration(WorksetConfigurationOption.OpenLastViewed);
options1.SetOpenWorksetsConfiguration(worksetConfig);
// Open the document
Document openedDoc = application.OpenDocumentFile(GetWSAPIModelPath("WorkaredFileSample.rvt"), options1);
return openedDoc;
}
private static ModelPath GetWSAPIModelPath(string fileName)
{
// Utility to get a local path for a target model file
FileInfo filePath = new FileInfo(Path.Combine(@"C:\Documents\Revit Projects", fileName));
ModelPath mp = ModelPathUtils.ConvertUserVisiblePathToModelPath(filePath.FullName);
return mp;
}
The following two examples demonstrate how to create a new local first from disk or from a Revit server, and then open it. Note that the sample below uses the GetWSAPIModelPath() method used in the previous example.
**Code Region: Open new local from disk**
---
public static Document OpenNewLocalFromDisk(UIApplication uiApplication)
{
// Create new local from a disk location
ModelPath newLocalPath = GetWSAPIModelPath("LocalWorksharing.rvt");
return (OpenNewLocalFromModelPath(uiApplication.Application, GetWSAPIModelPath("NewLocalWorksharing.rvt"), newLocalPath));
}
private static Document OpenNewLocalFromModelPath(Application app, ModelPath centralPath, ModelPath localPath)
{
// Create the new local at the given path
WorksharingUtils.CreateNewLocal(centralPath, localPath);
// Select specific worksets to open
// First get a list of worksets from the unopened document
IList<WorksetPreview> worksets = WorksharingUtils.GetUserWorksetInfo(localPath);
List<WorksetId> worksetsToOpen = new List<WorksetId>();
foreach (WorksetPreview preview in worksets)
{
// Match worksets to open with criteria
if (preview.Name.StartsWith("O"))
worksetsToOpen.Add(preview.Id);
}
// Setup option to open the target worksets
// First close all, then set specific ones to open
WorksetConfiguration worksetConfig = new WorksetConfiguration(WorksetConfigurationOption.CloseAllWorksets);
worksetConfig.Open(worksetsToOpen);
// Open the new local
OpenOptions options1 = new OpenOptions();
options1.SetOpenWorksetsConfiguration(worksetConfig);
Document openedDoc = app.OpenDocumentFile(localPath, options1);
return openedDoc;
}
The following example uses the OpenNewLocalFromModelPath() method demonstrated as part of the previous example.
**Code Region: Open new local from Revit Server**
---
/// <summary>
/// Get the server path for a particular model and open a new local copy
/// </summary>
public static Document OpenNewLocalFromServer(UIApplication uiApp)
{
// Create new local from a server location
Application app = uiApp.Application;
// Get the host id/IP of the server
String hostId = app.GetRevitServerNetworkHosts().First();
// try to get the server path for the particular model on the server
String rootFolder = "|";
ModelPath serverPath = FindWSAPIModelPathOnServer(app, hostId, rootFolder, "WorksharingOnServer.rvt");
ModelPath newLocalPath = GetWSAPIModelPath("WorksharingLocalFromServer.rvt");
return (OpenNewLocalFromModelPath(uiApp.Application, serverPath, newLocalPath));
}
/// <summary>
/// Uses the Revit Server REST API to recursively search the folders of the Revit Server for a particular model.
/// </summary>
private static ModelPath FindWSAPIModelPathOnServer(Application app, string hostId, string folderName, string fileName)
{
// Connect to host to find list of available models (the "/contents" flag)
XmlDictionaryReader reader = GetResponse(app, hostId, folderName + "/contents");
bool found = false;
// Look for the target model name in top level folder
List<String> folders = new List<String>();
while (reader.Read())
{
// Save a list of subfolders, if found
if (reader.NodeType == XmlNodeType.Element && reader.Name == "Folders")
{
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.EndElement && reader.Name == "Folders")
break;
if (reader.NodeType == XmlNodeType.Element && reader.Name == "Name")
{
reader.Read();
folders.Add(reader.Value);
}
}
}
// Check for a matching model at this folder level
if (reader.NodeType == XmlNodeType.Element && reader.Name == "Models")
{
found = FindModelInServerResponseJson(reader, fileName);
if (found)
break;
}
}
reader.Close();
// Build the model path to match the found model on the server
if (found)
{
// Server URLs use "|" for folder separation, Revit API uses "/"
String folderNameFragment = folderName.Replace('|', '/');
// Add trailing "/" if not present
if (!folderNameFragment.EndsWith("/"))
folderNameFragment += "/";
// Build server path
ModelPath modelPath = new ServerPath(hostId, folderNameFragment + fileName);
return modelPath;
}
else
{
// Try subfolders
foreach (String folder in folders)
{
ModelPath modelPath = FindWSAPIModelPathOnServer(app, hostId, folder, fileName);
if (modelPath != null)
return modelPath;
}
}
return null;
}
// This string is different for each RevitServer version
private static string s_revitServerVersion = "/RevitServerAdminRESTService2014/AdminRESTService.svc/";
/// <summary>
/// Connect to server to get list of available models and return server response
/// </summary>
private static XmlDictionaryReader GetResponse(Application app, string hostId, string info)
{
// Create request
WebRequest request = WebRequest.Create("http://" + hostId + s_revitServerVersion + info);
request.Method = "GET";
// Add the information the request needs
request.Headers.Add("User-Name", app.Username);
request.Headers.Add("User-Machine-Name", app.Username);
request.Headers.Add("Operation-GUID", Guid.NewGuid().ToString());
// Read the response
XmlDictionaryReaderQuotas quotas =
new XmlDictionaryReaderQuotas();
XmlDictionaryReader jsonReader =
JsonReaderWriterFactory.CreateJsonReader(request.GetResponse().GetResponseStream(), quotas);
return jsonReader;
}
/// <summary>
/// Read through server response to find particular model
/// </summary>
private static bool FindModelInServerResponseJson(XmlDictionaryReader reader, string fileName)
{
// Read through entries in this section
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.EndElement && reader.Name == "Models")
break;
if (reader.NodeType == XmlNodeType.Element && reader.Name == "Name")
{
reader.Read();
String modelName = reader.Value;
if (modelName.Equals(fileName))
{
// Match found, stop looping and return
return true;
}
}
}
return false;
}
## Open detached from central
If an add-in will be working on a workshared file but does not need to make permanet changes, it can open the model detached from the central file.
**Code Region: Open detached**
---
private static Document OpenDetached(Application application, ModelPath modelPath)
{
OpenOptions options1 = new OpenOptions();
options1.DetachFromCentralOption = DetachFromCentralOption.DetachAndDiscardWorksets;
Document openedDoc = application.OpenDocumentFile(modelPath, options1);
return openedDoc;
}
If an application only needs read-only access to a server file, the example below demonstrates how to copy the server model locally and open it detached. Note this code sample re-uses methods demonstrated in previous examples.
**Code Region: Copy and open detached**
---
public static Document CopyAndOpenDetached(UIApplication uiApp)
{
// Copy a server model locally and open detached
Application application = uiApp.Application;
String hostId = application.GetRevitServerNetworkHosts().First();
// Try to get the server path for the particular model on the server
String rootFolder = "|";
ModelPath serverPath = FindWSAPIModelPathOnServer(application, hostId, rootFolder, "ServerModel.rvt");
// For debugging
String sourcePath = ModelPathUtils.ConvertModelPathToUserVisiblePath(serverPath);
// Setup the target location for the copy
ModelPath localPath = GetWSAPIModelPath("CopiedModel.rvt");
// Copy, allowing overwrite
application.CopyModel(serverPath, ModelPathUtils.ConvertModelPathToUserVisiblePath(localPath), true);
// Open the copy as detached
Document openedDoc = OpenDetached(application, localPath);
return openedDoc;
}
**Parent page:** [Worksharing](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Worksharing_html.html)

View File

@@ -0,0 +1,221 @@
# Visibility and Display
# Visibility and Display
## Visibility
A worksets visibility can be set for a particular view using View.SetWorksetVisibility(). The WorksetVisibility options are Visible (it will be visible if the workset is open), Hidden, and UseGlobalSetting (indicating not to override the setting for the view). The corresponding View.GetWorksetVisibility() method retrieves the current visibility settings for a workset in that view. However, this method does not consider whether the workset is currently open. To determine if a workset is visible in a View, including taking into account whether the workset is open or closed, use View.IsWorksetVisible().
The class WorksetDefaultVisibilitySettings manages default visibility of worksets in a document. It is not available for family documents. If worksharing is disabled in a document, all elements are moved into a single workset; that workset, and any worksets (re)created if worksharing is re-enabled, is visible by default regardless of any current settings.
The following example hides a workset in a given view and hides it by default in other views.
**Code Region: Hide a Workset**
---
public void HideWorkset(Document doc, View view, WorksetId worksetId)
{
// get the current visibility
WorksetVisibility visibility = view.GetWorksetVisibility(worksetId);
// and set it to 'Hidden' if it is not hidden yet
if (visibility != WorksetVisibility.Hidden)
{
view.SetWorksetVisibility(worksetId, WorksetVisibility.Hidden);
}
// Get the worksets default visibility
WorksetDefaultVisibilitySettings defaultVisibility = WorksetDefaultVisibilitySettings.GetWorksetDefaultVisibilitySettings(doc);
// and making sure it is set to 'false'
if (true == defaultVisibility.IsWorksetVisible(worksetId))
{
defaultVisibility.SetWorksetVisibility(worksetId, false);
}
}
### Display Modes
In addition to getting and setting information about the workset visibility, the View class also provides methods to access information on the worksharing display mode and settings. The WorksharingDisplayMode enumeration indicates which mode a view is in, if any:
**Member Name** | **Description**
---|---
**Off** | No active worksharing display mode.
**CheckoutStatus** | The view is displaying the checkout status of elements.
**Owners** | The view is displaying the specific owners of elements.
**ModelUpdates** | The view is displaying model updates.
**Worksets** | The view is displaying which workset each element is assigned to.
**Code Region: Activate different worksharing display modes**
---
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
View activeView = commandData.View;
Document doc = activeView.Document;
// Prepare settings
Color red = new Color(0xFF, 0x00, 0x00);
WorksharingDisplayGraphicSettings settingsToApply = new WorksharingDisplayGraphicSettings(true, red);
// Toggle mode based on the current mode
using (Transaction t = new Transaction(doc, "Toggle display mode"))
{
t.Start();
WorksharingDisplaySettings settings = WorksharingDisplaySettings.GetOrCreateWorksharingDisplaySettings(doc);
switch (activeView.GetWorksharingDisplayMode())
{
case WorksharingDisplayMode.Off:
activeView.SetWorksharingDisplayMode(WorksharingDisplayMode.CheckoutStatus);
settings.SetGraphicOverrides(CheckoutStatus.OwnedByOtherUser, settingsToApply);
break;
case WorksharingDisplayMode.CheckoutStatus:
activeView.SetWorksharingDisplayMode(WorksharingDisplayMode.ModelUpdates);
settings.SetGraphicOverrides(ModelUpdatesStatus.UpdatedInCentral, settingsToApply);
break;
case WorksharingDisplayMode.ModelUpdates:
activeView.SetWorksharingDisplayMode(WorksharingDisplayMode.Owners);
settings.SetGraphicOverrides("Target user", settingsToApply);
break;
case WorksharingDisplayMode.Owners:
activeView.SetWorksharingDisplayMode(WorksharingDisplayMode.Worksets);
settings.SetGraphicOverrides(doc.GetWorksetTable().GetActiveWorksetId(), settingsToApply);
break;
case WorksharingDisplayMode.Worksets:
activeView.SetWorksharingDisplayMode(WorksharingDisplayMode.Off);
break;
}
t.Commit();
}
return Result.Succeeded;
}
### Graphics Settings
The WorksharingDisplaySettings class controls how elements will appear when they are displayed in any of the worksharing display modes. The colors stored in these settings are a common setting and are shared by all users in the model. Whether a given color is applied is specific to the current user and will not be shared by other users. Note that these settings are available even in models that are not workshared. This is to allow pre-configuring the display settings before enabling worksets so that they can be stored in template files.
**Code Region: Worksharing Display Graphic Settings**
---
public WorksharingDisplayGraphicSettings GetWorksharingDisplaySettings(Document doc, String userName, WorksetId worksetId, bool ownedbyCurrentUser)
{
WorksharingDisplayGraphicSettings graphicSettings;
// get or create a WorksharingDisplaySettings current active document
WorksharingDisplaySettings displaySettings = WorksharingDisplaySettings.GetOrCreateWorksharingDisplaySettings(doc);
// get graphic settings for a user, if specified
if (!String.IsNullOrEmpty(userName))
graphicSettings = displaySettings.GetGraphicOverrides(userName);
// get graphicSettings for a workset, if specified
else if (worksetId != WorksetId.InvalidWorksetId)
graphicSettings = displaySettings.GetGraphicOverrides(worksetId);
// get graphic settings for the OwnedByCurrentUser status
else if (ownedbyCurrentUser)
graphicSettings = displaySettings.GetGraphicOverrides(CheckoutStatus.OwnedByCurrentUser);
// otherwise get graphic settings for the CurrentWithCentral status
else
graphicSettings = displaySettings.GetGraphicOverrides(ModelUpdatesStatus.CurrentWithCentral);
return graphicSettings;
}
The overloaded method WorksharingDisplaySettings.SetGraphicOverrides() sets the graphic overrides assigned to elements based on the given criteria.
**Code Region: Graphic Overrides**
---
public void SetWorksharingDisplaySettings(Document doc, WorksetId worksetId, String userName)
{
String message = String.Empty;
// get or create a WorksharingDisplaySettings current active document
WorksharingDisplaySettings displaySettings = WorksharingDisplaySettings.GetOrCreateWorksharingDisplaySettings(doc);
// set a new graphicSettings for CheckoutStatus - NotOwned
WorksharingDisplayGraphicSettings graphicSettings = new WorksharingDisplayGraphicSettings(true, new Color(255, 0, 0));
displaySettings.SetGraphicOverrides(CheckoutStatus.NotOwned, graphicSettings);
// set a new graphicSettings for ModelUpdatesStatus - CurrentWithCentral
graphicSettings = new WorksharingDisplayGraphicSettings(true, new Color(128, 128, 0));
displaySettings.SetGraphicOverrides(ModelUpdatesStatus.CurrentWithCentral, graphicSettings);
// set a new graphicSettings by a given userName
graphicSettings = new WorksharingDisplayGraphicSettings(true, new Color(0, 255, 0));
displaySettings.SetGraphicOverrides(userName, graphicSettings);
// set a new graphicSettings by a given workset Id
graphicSettings = new WorksharingDisplayGraphicSettings(true, new Color(0, 0, 255));
displaySettings.SetGraphicOverrides(worksetId, graphicSettings);
}
The WorksharingDisplaySettings class can also be used to control which users are listed in the displayed users for the document. The RemoveUsers() method removes users from the list of displayed users and permanently discards any customization of the graphics. Only users who do not own any elements in the document can be removed. The RestoreUsers() method adds removed users back to the list of displayed users and permits customization of the graphics for those users. Note that any restored users will be shown with default graphic overrides and any customizations that existed prior to removing the user will not be restored.
**Code Region: Removing Users**
---
public void RemoveAndRestoreUsers(Document doc)
{
// get or create a WorksharingDisplaySettings current active document
WorksharingDisplaySettings displaySettings = WorksharingDisplaySettings.GetOrCreateWorksharingDisplaySettings(doc);
// get all users with GraphicOverrides
ICollection<string> users = displaySettings.GetAllUsersWithGraphicOverrides();
// remove the users from the display settings (they will not have graphic overrides anymore)
ICollection<string> outUserList;
displaySettings.RemoveUsers(doc, users, out outUserList);
// show the current list of removed users
ICollection<string> removedUsers = displaySettings.GetRemovedUsers();
String message = "Current list of removed users: ";
if (removedUsers.Count > 0 )
{
foreach (String user in removedUsers)
{
message += "\n" + user;
}
}
else
{
message = "[Empty]";
}
TaskDialog.Show("Users Removed", message);
// restore the previously removed users
int number = displaySettings.RestoreUsers(outUserList);
// again, show the current list of removed users
// it should not contain the users that were restored
removedUsers = displaySettings.GetRemovedUsers();
message = "Current list of removed users: ";
if (removedUsers.Count > 0 )
{
foreach (String user in removedUsers)
{
message += "\n" + user;
}
}
else
{
message = "[Empty]";
}
TaskDialog.Show("Removed Users Restored", message);
}
**Parent page:** [Worksharing](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Worksharing_html.html)

View File

@@ -0,0 +1,104 @@
# Worksets
# Worksets
Worksets are a way to divide a set of elements in the Revit document into subsets for worksharing. There may be one or many worksets in a document.
## Accessing worksets in the document
The document contains a WorksetTable which is a table containing references to all the worksets contained in that document. There is one WorksetTable for each document. There will be at least one default workset in the table, even if worksharing has not been enabled in the document. The Document.IsWorkshared property can be used to determine if worksharing has been enabled in the document. The WorksetTable class can be used to get the active workset (as shown in the example below) and to set the active workset, by calling SetActiveWorksetId().
**Code Region: Get Active Workset**
---
public Workset GetActiveWorkset(Document doc)
{
// Get the workset table from the document
WorksetTable worksetTable = doc.GetWorksetTable();
// Get the Id of the active workset
WorksetId activeId = worksetTable.GetActiveWorksetId();
// Find the workset with that Id
Workset workset = worksetTable.GetWorkset(activeId);
return workset;
}
## Filtering worksets
Since the Workset class is not derived from Element, use FilteredWorksetCollector to search, filter and iterate through a set of worksets. Conditions can be assigned to filter the worksets that are returned. If no condition is applied, this filter will access all of the worksets in the document. The WorksetKind enumerator is useful for filtering worksets as shown in the next example. The WorksetKind identifies the subdivision of worksets:
* **User** \- user managed worksets for 3D instance elements
* **Family** \- where family symbols & families are kept
* **Standard** \- where project standards live including system family types
* **Other** \- internally used worksets which should not typically be considered by applications
* **View** \- contain views and view-specific elements
**Code Region: Filtering Worksets**
---
public void GetWorksetsInfo(Document doc)
{
String message = String.Empty;
// Enumerating worksets in a document and getting basic information for each
FilteredWorksetCollector collector = new FilteredWorksetCollector(doc);
// find all user worksets
collector.OfKind(WorksetKind.UserWorkset);
IList<Workset> worksets = collector.ToWorksets();
// get information for each workset
int count = 3; // show info for 3 worksets only
foreach (Workset workset in worksets)
{
message += "Workset : " + workset.Name;
message += "\nUnique Id : " + workset.UniqueId;
message += "\nOwner : " + workset.Owner;
message += "\nKind : " + workset.Kind;
message += "\nIs default : " + workset.IsDefaultWorkset;
message += "\nIs editable : " + workset.IsEditable;
message += "\nIs open : " + workset.IsOpen;
message += "\nIs visible by default : " + workset.IsVisibleByDefault;
TaskDialog.Show("GetWorksetsInfo", message);
if (0 == --count)
break;
}
}
## Workset properties
The Workset class represents a workset in a Revit document. As is shown in the filtering worksets example above, the Workset class provides many properties to get information about a given workset, such as the owner and whether or not the workset is editable. These properties are read-only. To change the name of an existing workset, use the static method WorksetTable.RenameWorkset().
## Creating worksets
The static Workset.Create() method can be used to create a new workset in a given document with a specified name. Worksets can only be created in a document that has worksharing enabled and the name must be unique. The static method WorksetTable.IsWorksetNameUnique() will confirm if a given name is unique in the document. The following example demonstrates how to create a new workset.
**Code Region: Create a new workset**
---
public Workset CreateWorkset(Document document)
{
Workset newWorkset = null;
// Worksets can only be created in a document with worksharing enabled
if (document.IsWorkshared)
{
string worksetName = "New Workset";
// Workset name must not be in use by another workset
if (WorksetTable.IsWorksetNameUnique(document, worksetName))
{
using (Transaction worksetTransaction = new Transaction(document, "Set preview view id"))
{
worksetTransaction.Start();
newWorkset = Workset.Create(document, worksetName);
worksetTransaction.Commit();
}
}
}
return newWorkset;
}
**Parent page:** [Worksharing](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Worksharing_html.html)

View File

@@ -0,0 +1,177 @@
# Workshared File Management
# Workshared File Management
There are several Document methods for use with a workshared project file.
### Enable Worksharing
If a document is not already workshared, which can be determined from the Document.IsWorkshared property, worksharing can be enabled via the Revit API using the Document.EnableWorksharing() method. The document's Undo history will be cleared by this command, therefore this command and others executed before it cannot be undone. Additionally, all transaction phases (e.g., transactions, transaction groups and sub-transactions) that were explicitly started must be finished prior to calling EnableWorksharing().
#### Worksharing in the Cloud
* Document.EnableCloudWorksharing() converts a cloud model into a workshared cloud model.
* Document.CanEnableCloudWorksharing() can be used to check whether this operation is valid on a given model.
### Reload Latest
The method Document.ReloadLatest() retrieves changes from the central model (due to one or more synchronizations with central) and merges them into the current session.
The following examples uses ReloadLatest() to update the current session after confirming with the user that it is OK to do so.
**Code Region: Reload from Central**
---
public static void ReloadLatestWithMessage(Document doc)
{
// Tell user what we're doing
TaskDialog td = new TaskDialog("Alert");
td.MainInstruction = "Application 'Automatic element creator' needs to reload changes from central in order to proceed.";
td.MainContent = "This will update your local with all changes currently in the central model. This operation " +
"may take some time depending on the number of changes available on the central.";
td.CommonButtons = TaskDialogCommonButtons.Ok | TaskDialogCommonButtons.Cancel;
TaskDialogResult result = td.Show();
if (result == TaskDialogResult.Ok)
{
// There are no currently customizable user options for ReloadLatest.
doc.ReloadLatest(new ReloadLatestOptions());
TaskDialog.Show("Proceeding...", "Reload operation completed, proceeding with updates.");
}
else
{
TaskDialog.Show("Canceled.", "Reload operation canceled, so changes will not be made. Return to this command later when ready to reload.");
}
}
### Synchronizing with Central Model
The method Document.SynchronizeWithCentral() reloads any changes from the central model so that the current session is up to date and then saves local changes back to central. A save to central is performed even if no changes were made.
When using SynchronizeWithCentral(), options can be specified for accessing the central model as well as synchronizing with it. The main option for accessing the central is to determine how the call should behave if the central model is locked. Since the synchronization requires a temporary lock on the central model, it cannot be performed if the model is already locked. The default behavior is to wait and repeatedly try to lock the central model in order to proceed with the synchronization. This behavior can be overridden using the TransactWithCentralOptions parameter of the SynchronizeWithCentral() method.
The SynchronizeWithCentralOptions parameter of the method is used to set options for the actual synchronization, such as whether elements or worksets owned by the current user should be relinquished during synchronization.
In the following example, an attempt is made to synchronize with a central model. If the central model is locked, it will immediately give up.
**Code Region: Synchronize with Central**
---
public void SyncWithoutRelinquishing(Document doc)
{
// Set options for accessing central model
TransactWithCentralOptions transOpts = new TransactWithCentralOptions();
SynchLockCallback transCallBack = new SynchLockCallback();
// Override default behavior of waiting to try again if the central model is locked
transOpts.SetLockCallback(transCallBack);
// Set options for synchronizing with central
SynchronizeWithCentralOptions syncOpts = new SynchronizeWithCentralOptions();
// Sync without relinquishing any checked out elements or worksets
RelinquishOptions relinquishOpts = new RelinquishOptions(false);
syncOpts.SetRelinquishOptions(relinquishOpts);
// Do not automatically save local model after sync
syncOpts.SaveLocalAfter = false;
syncOpts.Comment = "Changes to Workset1";
try
{
doc.SynchronizeWithCentral(transOpts, syncOpts);
}
catch (Exception e)
{
TaskDialog.Show("Synchronize Failed", e.Message);
}
}
class SynchLockCallback : ICentralLockedCallback
{
// If unable to lock central, give up rather than waiting
public bool ShouldWaitForLockAvailability()
{
return false;
}
}
In the next example, the user is given a message prior to synching, and is given options on whether to relinquish all elements when synchronizing, or keep worksets checked out.
**Code Region: Synchronize with Central With Message**
---
public static void SynchWithCentralWithMessage(Document doc)
{
// Checkout workset (for use with "keep checked out worksets" option later)
FilteredWorksetCollector fwc = new FilteredWorksetCollector(doc);
fwc.OfKind(WorksetKind.UserWorkset);
Workset workset1 = fwc.First<Workset>(ws => ws.Name == "Workset1");
WorksharingUtils.CheckoutWorksets(doc, new WorksetId[] { workset1.Id });
// Make a change
using (Transaction t = new Transaction(doc, "Add Level"))
{
t.Start();
Level.Create(doc, 100);
t.Commit();
}
// Tell user what we're doing
TaskDialog td = new TaskDialog("Alert");
td.MainInstruction = "Application 'Automatic element creator' has made changes and is prepared to synchronize with central.";
td.MainContent = "This will update central with all changes currently made in the project by the application or by the user. This operation " +
"may take some time depending on the number of changes made by the app and by the user.";
td.AddCommandLink(TaskDialogCommandLinkId.CommandLink1, "Do not synchronize at this time.");
td.AddCommandLink(TaskDialogCommandLinkId.CommandLink2, "Synchronize and relinquish all elements.");
td.AddCommandLink(TaskDialogCommandLinkId.CommandLink3, "Synchronize but keep checked out worksets.");
td.DefaultButton = TaskDialogResult.CommandLink1;
TaskDialogResult result = td.Show();
switch (result)
{
case TaskDialogResult.CommandLink1:
default:
{
// Do not synch. Nothing to do.
break;
}
case TaskDialogResult.CommandLink2:
case TaskDialogResult.CommandLink3:
{
// Prepare to synch
// TransactWithCentralOptions has to do with the behavior related to locked or busy central models.
// We'll use the default behavior.
TransactWithCentralOptions twcOpts = new TransactWithCentralOptions();
// Setup synch-with-central options (add a comment about our change)
SynchronizeWithCentralOptions swcOpts = new SynchronizeWithCentralOptions();
swcOpts.Comment = "Synchronized by 'Automatic element creator' with user acceptance.";
if (result == TaskDialogResult.CommandLink3)
{
// Setup relinquish options to keep user worksets checked out
RelinquishOptions rOptions = new RelinquishOptions(true);
rOptions.UserWorksets = false;
swcOpts.SetRelinquishOptions(rOptions);
}
doc.SynchronizeWithCentral(twcOpts, swcOpts);
break;
}
}
}
### Create New Local Model
The WorksharingUtils.CreateNewLocal() method copies a central model to a new local file. This method does not open the new file. For an example of creating a new local model and opening it, see [Opening a Workshared Document](Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Worksharing_Opening_a_Workshared_Document_html.html).
**Parent page:** [Worksharing](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Worksharing_html.html)

View File

@@ -0,0 +1,27 @@
# Worksharing Overview
# Worksharing Overview
When creating add-ins for Revit, it is important to understand how documents function in a workshared environment. Whether the file is local, central or managed by Revit server affects how changes to the model will impact other users, or whether a model is potentially out of date or has worksets locked by another user.
## Workflow
This is the worksharing workflow from a high level perspective. When the user opens a central model, they get a local copy of the model. When they edit elements, the elements are checked out from the central model so that no one else can edit them. Local changes are only committed to the central model when a Synchronize with Central is performed. Once committed, other users can get the changes by performing a Reload Latest.
## Worksets
Elements are placed in worksets. An entire workset can be checked out so that the user has exclusive editing rights to all the elements in the workset. If new elements are added, they are placed in the active workset in the local model.
Specific worksets can be opened with the model. Only opened worksets are visible, but all elements are available in the model. A workshared model may also be open "detached", in which there is no possibility of updating the central model. In this case, no workset management is required.
## Worksharing types
There are three types of worksharing:
* **File-based** \- The central model is accessible on disk over the network
* **Server-based** \- Revit server manages the central model and possibly locally available accelerators
* **Cloud-based** \- Uses the Revit Cloud Worksharing service to author Revit models in the cloud concurrently with other team members
**Parent page:** [Worksharing](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Worksharing_html.html)

View File

@@ -0,0 +1,19 @@
# Worksharing
# Worksharing
Worksharing is a design method that allows multiple team members to work on the same project model at the same time. When worksharing is enabled, a Revit document can be subdivided into worksets, which are collections of elements in the project.
**Pages in this section**
* [Worksharing Overview](Worksharing/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Worksharing_Worksharing_Overview_html.html)
* [Worksets](Worksharing/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Worksharing_Worksets_html.html)
* [Elements in Worksets](Worksharing/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Worksharing_Elements_in_Worksets_html.html)
* [Editing Elements in Worksets](Worksharing/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Worksharing_Editing_Elements_in_Worksets_html.html)
* [Opening a Workshared Document](Worksharing/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Worksharing_Opening_a_Workshared_Document_html.html)
* [Visibility and Display](Worksharing/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Worksharing_Visibility_and_Display_html.html)
* [Workshared File Management](Worksharing/Revit_API_Revit_API_Developers_Guide_Advanced_Topics_Worksharing_Workshared_File_Management_html.html)
**Parent page:** [Advanced Topics](../Revit_API_Revit_API_Developers_Guide_Advanced_Topics_html.html)

View File

@@ -0,0 +1,39 @@
# Common Definitions
# Common Definitions
### Ribbon
The horizontally-tabbed user interface across the top of (the application frame in) Revit 2010 and later.
### Ribbon Tab
The ribbon is separated into tabs. The Add-Ins ribbon tab, which only appears when at least one add-in is installed, is available for third party developers to add a panel.
### Ribbon Panel
A ribbon tab is separated into horizontal groupings of commands. An Add-In panel represents the commands available for a third party developer's application. The Add-In panel is equivalent to the toolbar in Revit 2009.
### Ribbon Button
The button is the mechanism for launching a command. They can either be large, medium or small. Both large and small buttons can either be a simple push button or a drop-down button.
### Menu button
The default first panel on the Add-Ins tab is the External Tools panel that contains one button titled "External Tools." The External Tools menu-button is equivalent to the Tools > External Tools menu in Revit 2009. Any External Commands registered in a .addin manifest file will appear in this menu button.
**Figure 240 - External Tools menu-button on Add-Ins tab**
### Drop-down button
A drop-down button expands to show two or more commands in a drop-down menu. Each sub-command can have its own large icon.
### Vertical Separator
A vertical separator is a thin vertical line that can be added between controls on a panel.
### Tooltip
A tooltip is a small panel that appears when the user hovers the mouse pointer over a ribbon button. Tooltips provide a brief explanation of the commands expected behavior.
**Parent page:** [API User Interface Guidelines](../Revit_API_Revit_API_Developers_Guide_Appendices_API_User_Interface_Guidelines_html.html)

View File

@@ -0,0 +1,7 @@
# Consistency
# Consistency
It is important for applications based on the API to provide a user experience that is consistent with Revit. This will allow the users of your application to leverage knowledge they developed while learning Revit. Consistency can be obtained by re-using certain dialog types, instead of creating or re-creating dialogs. See the dialog types section for examples of dialogs you can leverage when creating your application.
**Parent page:** [API User Interface Guidelines](../Revit_API_Revit_API_Developers_Guide_Appendices_API_User_Interface_Guidelines_html.html)

View File

@@ -0,0 +1,936 @@
# Dialog Guidelines
# Dialog Guidelines
A dialog is a separate controllable area of the application that contains information and/or controls for editing information. Dialogs are the primary vehicle for obtaining input from and presenting information to the user. Use the following guidelines when deciding which dialog to use.
**Dialog Type** | **Definition** | **Use When**
---|---|---
Modal | Halts the rest of the application and waits for user input |
* Task(s) in the dialog are infrequent
* It is acceptable to halt the system while the user enters data
Modeless | User can switch between the dialog and the rest of the application without closing the dialog |
* Task(s) in the dialog are frequent
* Halting the system would interrupt the user workflow
## Behavior Rules
* A dialog can either be user initiated (prompted by clicking a control) or system initiated (a warning triggered by a system event)
* The initial dialog location typically should be centered on the screen, but this rule may vary based on variation or on a particular context of use, but should have an immediate focus
* Dialogs should be resizable when the content is dynamic, please see Dynamic Layout section below for more on this topic
## Dialog Controls
**Control** | **Use When** | **Example**
---|---|---
[CHECK BOX](https://docs.microsoft.com/en-us/windows/win32/uxguide/guidelines) | The choice being made (and its opposite) can be clearly expressed to the user with a single label | The opposite of enable is disable
[RADIO BUTTON](https://docs.microsoft.com/en-us/windows/win32/uxguide/guidelines) | There are between 2 - 5 mutually exclusive but related choices and the user can only make one selection per choice |
[TEXT BOX](https://docs.microsoft.com/en-us/windows/win32/uxguide/guidelines) | This choice requires manually entering a numerical text value |
[DROP DOWN LIST](https://docs.microsoft.com/en-us/windows/win32/uxguide/guidelines) | Select from a list of mutually exclusive choices It is appropriate to hide the rest of the choices and only show the default selection Also, use this instead of radio buttons when there are more than four choices or if real estate is limited |
[COMBO BOX](https://docs.microsoft.com/en-us/windows/win32/uxguide/guidelines) | Similar to a drop-down list box, but allows the user to enter information not pre-populated in the drop-down |
[SLIDER](https://docs.microsoft.com/en-us/windows/win32/uxguide/guidelines) | Use when the expected input or existing data will be in a specific range. Sliders can also be combined with text boxes to give additional level of user control and give feedback as the slider is moved |
[SPINNER](https://docs.microsoft.com/en-us/windows/win32/uxguide/guidelines) | Use this option if the data can be entered sequentially and has a logical limit. This can be used in conjunction with an editable text box |
## Laying Out a Dialog
### Basic Elements
Every dialog contains the following elements:
| Element | Requirements | Illustration
---|---|---|---
1 | _Title bar_ | Title bars text describes the contents of the window. |
2 | _Help button_ | A button in the title bar next to the close button.
* Help button is optional - use only when a relevant section is available in the documentation
* Note that many legacy dialogs in Revit still have the Help button located in the bottom right of the dialog
3 | _Controls_ | The bulk of a dialog consists of controls used to change settings and/or interact with data within an application. The layout of the controls should follow the Layout Flow, Spacing and Margins, Grouping and Dialog Controls sections outlined below. When an action control interacts with another control, such as a text box with a Browse button, denote the relationship by placing the _RELATED_ controls in one of three places:
* To the right of and top-aligned with the other control
* Below and left-aligned with the other control. See Content Editor
* Vertically centered between related controls. See List Builder
4 | _Commit Buttons_ | See the Committing Changes section. The most frequently-used Commit buttons include:
* OK
* Cancel
* Yes
* No
* Retry
* Close
### Layout Flow
When viewing a dialog within a user interface, the user has multiple tasks to accomplish. How the information is designed and laid out must support the user in accomplishing their task(s). Keeping this in mind, it is important to remember users:
* Scan (not read) an interface and then stop when they get to what they were looking for and ignore anything beyond it
* Focus on items that are different
* Not scroll unless they need to
Lay out the window in such a way that suggests and prompts a "path" with a beginning, middle, and end. This path should be designed to be easily scanned. The information and controls in the "middle" of the path must be designed to be well balanced and clearly delineate the relationship between controls. Of course, not all users follow a strictly linear path when completing a task. The path is intended for a typical task flow.
_Variation A: Top-Down_ _Place UI items that:_
1. Initiate a task in the upper-left corner or upper-center
2. User must interact with to complete the task(s) in the middle
3. Complete the task(s) in the lower-right corner
In this example (Materials dialog), the user does the following:
1. Searches/filters the list
2. Selects an item
3. Commits or Cancels
_Variation B: Left-Right_ _Place UI items that:_
1. Initiate a task or change between modes in the far left
2. User must interact with to complete the task(s) in the middle. This may be separated into separate distinct sections
3. Complete the task(s) in the lower-right corner
| **Figure 198 - Materials dialog**
---|---
**Figure 199 - Revit File Open dialog**
Note: A top-down flow can also be used within this dialog, if they user is browsing the file hierarchy instead of the shortcuts on the far left.
### Variation C: Hybrid
As seen in Variation B, many windows that are laid out left to right are actually a hybrid of left-right and top-down.
**Figure 200 - Revit Filters dialog**
In this example (Revit Filters), the three primary tasks are grouped into columns, delineated by the group boxes: Filters, Categories and Filter Rules. Each of these columns contains a top-down flow that involves selecting from a collection of items or modifying a control.
### Spacing and Margins
The following table lists the recommended spacing between common UI elements (for 9 pt. Segoe UI at 96 dpi). For a definition of the difference between dialog units (DLU) and relative pixels.
### Spacing and Margins Table
**Element** | **Placement** | **Dialog units** | **Relative pixels**
---|---|---|---
| Dialog box margins | 7 on all sides | 11 on all sides
| Between text labels and their associated controls (for example, text boxes and list boxes) | 3 | 5
| Between related controls | 4 | 7
| Between unrelated controls | 7 | 11
| First control in a group box | 11 down from the top of the group box; align vertically to the group box title | 16 down from the top of the group box; align vertically to the group box title
| Between controls in a group box | 4 | 7
| Between horizontally or vertically arranged buttons | 4 | 7
| Last control in a group box | 7 above the bottom of the group box | 11 above the bottom of the group box
| From the left edge of a group box | 6 | 9
| Text label beside a control | 3 down from the top of the control | 5 down from the top of the control
| Between paragraphs of text | 7 | 11
| Smallest space between interactive controls | 3 or no space | 5 or no space
| Smallest space between a non-interactive control and any other control | 2 | 3
| When a control is dependent on another control, it should be indented 12 DLUS or 18 relative pixels, which by design is the distance between check boxes and radio buttons from their labels. | 12 | 18
### Grouping
Group boxes are the most common solution used to explicitly group related controls together in a dialog and give them a common grouping.
**Figure 201 - Group box within a standard Print dialog**
A group box should include:
* Two or more related controls
* Exists with at least one other group box
* A label that:
* describes the group
* follows sentence style
* is in the form of a noun or noun phrase
* does not use ending punctuation
* A Spacing and Margins section describes spacing rules
### Poor Examples- What Not to Use
The following are examples of what _should not_ be done:
Group boxes without a label or a group box with only one control.
One group box in a dialog.
The (Materials) single group box title is redundant with the dialog title and can be removed.
**Figure 202 - Group box with no label and group box with one control and Group box with title that is redundant with dialog title**
Avoid "nesting" two of more group boxes within one another and placing Commit buttons inside a group box.
### Horizontal Separator
An alternative to the traditional group box is a horizontal separator. Use this only when the groups are stacked vertically in a single column.
The following example is from Microsoft Outlook 2007:
**Figure 203 - Horizontal separators in Microsoft Outlook 2007**
Spacing between the last control in the previous group and the next grouping line should be 12 DLUs (18 relative pixels).
### Dynamic Layout
Content that is presented on different types or sizes of display devices usually requires the ability to adapt to the form that it is displayed in. Using a dynamic layout can help when environment changes such as localizing to other languages, changing the font size of content, and for allowing user to manually expand the window to see more information.
To create a dynamic layout:
* Treat the content of the window as dynamic and expand to fill the shape of its container unless constrained.
* Add a resizing grip to the bottom right corner of the dialog.
* The dialog should not be resizable to a size smaller than the default size.
* The user defined size should be remembered within and between application sessions.
* Elements in the dialog should maintain alignment during resizing based on the quadrant they are described in the following table:
**Home Quadrant** | **Alignment**
---|---
1 | Left and Top
2 | Right and Top
3 | Left and Bottom
4 | Right and Bottom
Multiple | If control is located in multiple quadrants, it should anchor to quadrant 1 and/or 3 (to the left) and expand/contract to the right to maintain alignments
**Figure 204 - Four square grid applied to Revit View Templates dialog to demonstrate how it should be resized**
In this example, the list box is located in all four quadrants. So, it is anchored to the top-left and expands to the right and to the bottom.
### Implementation Notes
Here are the some steps to consider when implementing a dynamic layout:
* Break the design on sections based on the structure of the content and flow you would like to achieve when container's size changes.
* Define the minimum, maximum and other size constrains for the various sections and control used. This is usually driven by the purpose of the data type we are presenting, images, supplemental information and controls.
* Consider alignment, that is, how the content will flow when re-sized. Consider which items should be static and which dynamic and how they are expandable - which should usually be for left-to-right languages, and dialogs should flow to the right and bottom, being anchored and aligned to the top and left.
For guidelines on how different controls should handle resizing, see the table below:
**Control** | **Content** | **Re-sizable** | **Moveable**
---|---|---|---
_Button_ | Static | No | Yes
_Link_ | Static | No | Yes
_Radio Button_ | Static | No | Yes
_Spin Control_ | Static | No | Yes, based on the element to which it is attached
_Slider_ | Static | X Direction | Yes
_Scroll Bar_ | Static | X Direction | Yes
_Tab_ | Dynamic | X and Y Direction | Yes, but not smaller then the biggest control contained
_Progressive Disclosure_ | Dynamic | X and Y Direction | Yes, but not smaller then the biggest control contained
_Check Box_ | Static | No | Yes
_Drop-Down List_ | Dynamic | X Direction | Yes but not smaller then the biggest text contained.
_Combo Box_ | Dynamic | X and Y Direction | Yes, but not smaller then the biggest text contained
_List View_ | Dynamic | X and Y Direction | Yes, but not smaller then the biggest text contained
_Text Box_ | Dynamic | X and Y if multi-line | Yes
_Date Time Box_ | Dynamic | X Direction | Yes, but not smaller then the biggest text contained
_Tree View_ | Dynamic | X and Y Direction | Yes, but not smaller then the biggest text contained
_Canvas_ | Dynamic | X and Y Direction | Yes
_Group Box_ | Dynamic | X and Y Direction | Yes, but not smaller then the biggest control contained
_Progress Bar_ | Static | X | Yes
_Status Bar_ | Dynamic | X | Yes
_Table or data grid_ | Dynamic | X and Y | Yes, table columns should grow proportionally in the X direction
## Dialog Types
There are a handful of dialog types that persist throughout the Revit products. Utilizing these standard types helps to drive consistency and leverage users' existing learning and knowledge patterns.
### Standard input dialog
This is the most basic dialog type. This should be used when the user needs to make a number of choices and then perform a discrete operation based on those choices. Controls should follow rules for Grouping, Spacing and Margins, and Layout Flow.
The Revit Export 2D DWF Options dialog is a good example of a Standard Input dialog.
**Figure 205 - The Export 2D DWF Options dialog**
### Property Editor
Use when an item's properties need to be modified by the user. To create a property editor, provide a Table View that presents a name/property pair. The property field can be modified by a Text Box, Check Box, Command Button, Drop-Down List, or even a slider.
**Figure 206 - Property Grid**
### Supported Behaviors
**ID** | **Behavior** | **Description** | **Required**
---|---|---|---
1 | Filter | Filters the list of properties based on specified criteria | No
2 | Grouping | Grouping the properties makes them easier to scan | No
3 | Controls (Edit properties of an item) | Each value cell can contain a control that can be edited (or disabled) depending on the context | Yes
4 | Commit (Buttons) | Optional, only use if within a modal dialog | No
### Content Editor
If multiple action controls interoperate with the same content control (such as a list box), vertically stack them to the right of and top-aligned with the content control, or horizontally place them left-aligned under the content control. This layout decision is at the developer's discretion.
**Figure 207 - Action controls to the right of content and action controls below content**
### Collection Viewer
In applications such as Revit, the user must view and manage collections of items to complete their tasks. The Collection View provides the user a variety of ways of viewing the items (browsing, searching and filtering) in the collection. Provide a way for a user to easily browse through a collection of items for the purpose of selecting an item to view or edit. Optionally provide the ability to search and/or filter the collection.
**Figure 208 - Materials dialog from Revit**
The example above shows Collection Viewer represented as a List. Table View and Tree View are also options for displaying the collection items.
### Supported Behaviors
| **Action** | **Description** | **Required**
---|---|---|---
_1_ | Filter | This provides options for filtering the list view. This can be represented as a:
* Drop down - default criteria must be selected and should include "All" as an option
* Check boxes - check box ON would refine the list. Default set by designer
* Radio buttons - choosing between radio buttons refines the list. Default set by designer Once a choice is selected, the collection will automatically update based on the selected criteria. Controls must follow the [Microsoft Windows User Experience Guidelines](https://docs.microsoft.com/en-us/windows/win32/uxguide/guidelines)
| No
_2_ | Search Box | A search box allows users to perform a keyword search on a collection. The search box must follow [No ](http://https://docs.microsoft.com/en-us/windows/win32/uxguide/guidelines</a>%0A%0A</td>%0A%0A<td class=)
_3_ | Change viewing mode | If the collection is viewed as list, the items can be optionally displayed with small or large icons instead of text | No
_4_ | Collection Manager |
* A separate UI will be provided to edit, rename, delete or add items to the collection.
* This is only displayed if managing the collection is user-editable
| No
_5_ | View the collection | The collection itself can be viewed in the following ways: List View, Table View, Tree View, or as a Tree Table | Yes
_6_ | Show More | This button hides/shows the additional data associated with the currently selected item. | No
### List View
When the user needs to view and browse and optionally select, sort, group, filter, or search a flat collection of items. If the list is hierarchical, use Tree View or Tree Table and if the data is grouped into two or more columns, use Table View instead.
**Figure 209 - List View, showing different ways of presenting the data**
There are four basic variations of this pattern that includes the following:
### Drop down list
Use a drop down list box when you only need to present a flat list of names, only a single selection is required and space is limited. The [Microsoft Windows User Experience Guidelines](https://docs.microsoft.com/en-us/windows/win32/uxguide/guidelines) should be followed when using a drop-down list.
**Figure 210 - Drop-down list**
### Combo box
Use a combo box when you want the functionality of the drop-down list box but also need to the ability to edit the drop-down list box. The [Microsoft Windows User Experience Guidelines](https://docs.microsoft.com/en-us/windows/win32/uxguide/guidelines) should be followed when using this option, including for how to decide between drop-down and combo box.
**Figure 211 - The font selector in Microsoft Office 2007 is an example of a combo box**
### List box
Use when you only need to present a - list of names, it benefits the user to see all items and when there is sufficient room on the UI to display list box. Use also if selecting more than one option is required. The [Microsoft Windows User Experience Guidelines](https://docs.microsoft.com/en-us/windows/win32/uxguide/guidelines) should be followed when using a list box.
**Figure 212 - List box**
### List View
Use when the data includes the option of list, details and/or graphical thumbnail previews, such as a Windows Open Dialog.
**Figure 213 - List view**
### Table View
Users often need to view the contents of a collection so that they can easily comprehend and compare the attributes of many items at once. To accommodate this, present the user with a table that is formatted in such a way that is conducive to scanning.
### Examples
Good Example - The following is an example of a well-formatted table.
Note: The header cells are differentiated from the data cells and the alignment differs to makes it easier to scan the data.
**Figure 214 - Good table example**
Poor Example - The following is an example of a poorly formatted table.
Note: The header cells are not differentiated from the data cells and the alignment makes it difficult to scan the data.
**Figure 215 - Bad table example**
## Table title and header cells
* Highlight and bold the table title to differentiate it from the data cells and the header cells
* For columns that are sort able, clicking the header sorts the collection. To differentiate table rows from each other, a different shade is used as background color for every second row. Keep the difference between the two colors to a minimum to preserve a gentle feeling. The colors should be similar in value and low in saturation - the one should be slightly darker or lighter than the other. It is often seen that one of the two colors is the background color of the page itself
* Ensure that the colors are different than header and title rows
* Title and header cells should be in title case
## Columns containing numeric data
* Right align the column heading_s_ for the data column
* Right (decimal) align data in numeric columns
* Format the values in percentage columns with percentage signs immediately to the right of the values to ensure that users are aware that the values are percentages
Note: People can easily forget that they are looking at percentages so the redundancy is important here, especially for tables with many values
## Columns containing numerical data
* Right align the column headings for the data column
* Right (decimal) align data in financial columns
## Columns with a mix of positive and negative numeric data
Align the data so that decimals align
**Figure 216 - Properly aligned numeric data**
## Columns containing only single letter or control (such as check box)
* Center the data or check symbol in this column
* Center the heading for the column
## Columns with text that does not express numbers or dates
* Left align the column header of the number column
* Left align the text data
* Left align data that are not used as numbers like product IDs or registration numbers
## Columns containing dates (treat dates as text)
* Left align the column header of a date column
* Left align the dates
* Include a date format in the column header if you are presenting to an international audience to avoid confusion
## Column Sorter
Use a column sorter when users are viewing a collection (such as a large table), possibly spanning multiple pages, that they must scan for interesting values.
There are several meaningful possibilities for sorting the table and users may be more effective if they can dynamically change the column that is used for sorting the values on.
* Allow users to sort a collection of items by clicking on a column header
* As users click on the column label, the table is sorted by that column
* Another click reverses the order, which should be visualized using an up or down-wards pointing arrow
* Make sure it is visible which columns can be clicked on and which one is active now
**Figure 217 - Column sorter**
## Tree View
Often a user may need to understand complex relationships within a hierarchy of items and this can often best displayed within a "tree view." The user may also need to select one or more of the items. If the collection is a flat list, use the List View and if the data is grouped into two or more columns, use Table View or Tree Table instead.
A tree UI follows the principle of user initiated [Progressive Disclosure](./Revit_API_Revit_API_Developers_Guide_Appendices_API_User_Interface_Guidelines_Progressive_Disclosure_html.html). Using a tree allows complex hierarchical data to be presented in a simple, yet progressively complex manner. If the data becomes too broad or deep, a search box should be considered.
**Figure 218 - The Revit Project Browser is a good example of a tree view**
### Tree Table
As with a Tree View, the user may need to view and browse a hierarchically organized collection of items with the intent of selecting one or more of the items. However, the user also needs to see more properties of the item than just the name. To accommodate this, present the user with a tree embedded within a table. Each row presents additional attributes of the item. Expanding a node exposes another row.
**Figure 219 - The Revit Visibility/Graphics dialog is a good example of a Tree Table Collection Search / Filter**
When the user is viewing a collection with many items, they may need to filter the number of items. To accomplish this, provide a way for the user choose between either a system-provided list of filter criteria and/or user-creatable criteria. Selecting the criteria automatically filters the collection. The two most common ways are demonstrated in the Revit Materials dialog.
* A search box allows the list to be filtered based on a keyword
* A drop-down allows the list to be filtered based on a set of defined criteria
### Collection Editor
In addition to viewing a collection of items, a user will also typically want to edit the collection. This can be accomplished by associating a toolbar for editing, creating, duplicating, renaming, and deleting items.
### The Edit Bar
The buttons should be ordered left to right in the following order and with the following as tooltip labels: Edit, New, Duplicate, Delete, Rename. If a feature does not utilize one or more buttons, the rest move to the left.
**Figure 220 - The Edit Bar**
| **Action** | **Context**
---|---|---
1 | Edit | Use If an item can be edited. Editing an item may launch a separate dialog if there are less than three properties to edit. See the Collection Viewer section for more details on displaying collection items
2 | New | Use New if the application is creating a new item
3 | Duplicate | Use Duplicate if the feature can only duplicate existing items
4 | Rename | Use Rename if the feature allows items to be renamed
5 | Delete | Use Delete to remove the feature
To ensure that the primary UI element is placed first in the layout path, the following rules should be followed when placing the manage controls:
* Navigating list is primary task: place at the bottom-left of the list control
* Managing list is primary task: place at top left of list control
* When the main collection being managed is represented as a combo box: place to the right of the combo box
### Add/Remove
A slight variation on the Edit Bar is the use of Add and Remove buttons, denoted by plus and minus icons, as shown below. Add and Remove is used when data is being added to an existing item in the model.
The following is a good example of a Collection Editor dialog that uses both forms of the Edit Bar. The Add (+) and Remove (-) buttons are used to add values to an already existing demand factor type.
**Figure 221 - Demand Factors dialog in Revit MEP 2011**
### List Builder
Use when there is a number of items that the user has to add/remove from one list to another. This is typically used when there is a list (located on the right) that needs to have items added to it from an existing list (located on the left.) Provide a List Box View of the two lists with button controls between, one for adding and the other for removing items.
**Figure 222 - The Curtain System SDK sample**
### Supported Behaviors
| **Action** | **Description** | **Required**
---|---|---|---
1 | Add (to list) | Takes an item from list A and adds it to list B | Yes
2 | Remove (from list) | Removes item from List B | Yes
3 | Collection Editor | If List A can be managed in this context, use Collection Manager | No
Depending on the feature, the List Builder can act in one of two ways:
* Item can only be added once items from List A can only be added to List B once. In this case, the Add button should be disabled when a previously added item is selected in List A.
* Item can be added multiple times. In this case, the Add button is not disabled, and the user can add an item from List A to List B multiple times (the amount determined by the feature.) See Edit Label example below.
If the user needs to arbitrarily move an item up or down in a collection, provide up/down buttons next to the list.
**Figure 223 - Up/down buttons**
### Task Dialog
Task dialogs are a type of modal dialog. They have a common set of controls that are arranged in a standard order to assure consistent look and feel.
A task dialog is used when the system needs to:
* provide users with information
* ask users a question
* or allow users to select options to perform a command or task
The image below shows a mockup of a task dialog with all possible controls enabled. Most of the controls shown are optional and one would never create a task dialog that had everything on. The mockup below simple illustrates all the parts of a task dialog that could be utilized in one image.
**Figure 224 - A task dialog with all components visible**
Note: This particular task dialog would never happen in a real implementation. Only a small subset would ever be used at one time. Task dialogs cannot display other controls such as, text inputs, list boxes, combo boxes, check boxes, etc. They also only accommodate single step, single action operations; meaning a user may make a single choice and complete the task dialog operation. As a result any dialog that requires such additional controls or multiple steps operations (as with a wizard) are not task dialog candidates. They would need to be implemented as custom dialogs using .NET controls to have a similar look & feel to Task Dialogs. The sections to follow explain when, where and how each task dialog component should be used to be consistent with others in Autodesk products.
#### General Design Principles
These are a few guiding principles that can be applied globally to task dialogs.
When reviewing the contents of a task dialog ask:
* Does it provide all the information needed to take informed action?
* Is the information too technical or jargon filled to be understood by the target user?
#### The following points apply to English language versions of product releases
* Text should be written in sentence format - normal capitalization and punctuation. Titles and command button text are the exceptions, which are written in title format.
* Use a _single space_ after punctuation. For example, DO NOT put two spaces after a period at the end of a sentence. Avoid the use of parentheses to address plurals. Instead, recast sentences. For example: _Write "At least one referenced drawing contains one or more objects that were created in…" instead of "The referenced drawing(s) contains object(s) that were created in …"_
* Include a copyright symbol © after any third party application called out in a task dialog.
#### Title (required)
All task dialogs require a title. Titles of task dialogs should be descriptive and as unique as possible. Task dialog titles should take the format of the following:
`<featureName> - <shortTitle>`
* Where `<featureName>` is the module from which the task dialog was triggered
* And `<shortTitle>` is the action that resulted in the task dialog being shown
* Examples:
* _Reference Edit - Version Conflict_
* _Layer - Delete_
* _BOM - Edit Formula_
Where possible, use verbs on the second `<shortTitle>` part of the title such as Create, Delete, Rename, Select, etc.
In cases where there is no obviously applicable feature name (or several) applying a short title alone is sufficient.
A task dialog title should never be the product name, such as AutoCAD Architecture.
#### Title bar Icon
The icon appearing in the far left to the title bar should be that of the host application - this includes third party plug-ins. Task dialogs may contain plug-in names in the title to specify the source of the message, but the visual branding of all task dialogs should match the host application; such as Revit, Inventor, AutoCAD Electrical, etc.
#### Main Instructions (required)
This is the large primary text that appears at the top of a task dialog.
* Every task dialog should have main instructions of some kind
* Text should not exceed three lines
* _**[English Language Versions]**_ Main instructions should be written in sentence format - normal capitalization and punctuation
* _**[English Language Versions]**_ Address the user directly as "you"
* _**[English Language Versions]**_ When presented with multiple command link options the standard final line for the main instructions should be, "What do you want to do?"
**Figure 225 - A very simple task dialog with only main instructions for text**
#### Main Content (optional - commonly used)
This is the smaller text that appears just below the main instructions.
* Main content is optional. It's primarily used when all the required instructions for a task dialog will not fit in the main instruction area
* Main content should not simply restate the main instructions in a different way, it should contain additional information that builds upon or reinforces the main instructions
* _**[English Language Versions]**_ Main instructions should be written in sentence format (normal capitalization and punctuation)
* _**[English Language Versions]**_ Address the user directly as "you" when needed
**Figure 226 - A task dialog that uses both main instructions and main content**
#### Expanded Content (optional - rarely used)
This text is hidden by default and will display at the bottom of the task dialog when the "Show" button is pressed.
* Expanded content is optional, and should be rarely used. It is used for information that is not essential (advance or additional information), or that doesn't apply to most situations
* _**[English Language Versions]**_ Expanded content should be written in sentence format (normal capitalization and punctuation)
* _**[English Language Versions]**_ Address the user directly as "you" when needed
**Figure 227 - The Show Details button displays additional Main Content text**
#### Main Image (optional - low usage)
Task dialogs support the inclusion of an image to the left of the main instructions. Prior to task dialogs it has been common for most dialogs to have some sort of icon to show that the information it contained was informative, a warning, and error, etc.
Because images were used all the time the value of any image in a dialog was low.
_For Autodesk products the warning icon (exclamation point in a yellow triangle) should only be used in situations where a possible action will be destructive in some way and likely cause loss of data or significant loss of time in rework._
A few examples include:
* Overwriting a file
* Saving to an older or different format where data may be lost
* Permanently deleting data
* Breaking associations between files through moving or renaming
This is only a partial list. With the exception of such situations _usage of a main image should be avoided_. See Figure 228 for an example of a Task Dialog with a warning icon.
#### "Do not show me again" (DNSM) Checkbox (optional)
Task dialogs support a "Do not show me again" checkbox that can be enabled on dialogs that users can opt to not see in the future. The standard wording for the label on this checkbox for English language versions is:
_"Do not show me this message again"_
Do not is not contracted to "Don't" and there is no punctuation at the end of the line.
For the single action the working should be "Always `<action>`" - for example
* If the action is "Save current drawing" the checkbox label would read "Always save current drawing"
* If the action is "Convert objects to linework" the checkbox label would read "Always convert objects to linework"
**Figure 228 - Example of a task dialog using the DNSMA checkbox as an "Always…" checkbox for one choice**
Where multiple are choices possible:
* The generic wording "_Always perform my current choice_ " should be used
* Command links should be used to show the available choices. If buttons are used and a Cancel button is included it looks as though "cancel" is an option that could always be performed in future
#### Footer Text (optional)
Footer text is used to link to help. It replaces the Help or "?" button found on previous dialogs, and will link to the same location as an existing help link. On English language versions the text in the footer should read:
"Click here to learn more"
The text should be written as a statement in sentence format, but with no final punctuation. See Figure 226 for an example of a Task Dialog with footer text.
#### Progress Bar (optional - rarely used)
In instances where a task dialog is showing progress, or handling of an available option may take several seconds or more a progress bar can be used.
#### Command Links (optional - commonly used)
In task dialogs there are two ways a user can select an action - command links and commit buttons.
Command links are used in the following situations:
* More than one option is available (avoid situations where only one command link is shown)
* And a short amount of text would be useful in helping a user determine the best choice
Command links handle scenarios such as:
* Do A, B, or C
* Do A or B or A and B
* Do A or do not do A
* Etc
Command link text has two parts:
1. _Main content:_ This is required for any command link. It is one line, written as a statement. For English language versions it is in sentence format without final punctuation.
2. _Supplemental content:_ This is optional additional text to clarify the main content. For English language versions it is written in normal sentence format with final punctuation.
The first command link (one at the top) is the default action for the task dialog. It should be the most common action or the least potentially damaging action if no choice is substantially more likely than the other for the common use case.
**Figure 229 - A task dialog with two command links**
**Figure 230 - Task Dialog with command links and a command button**
#### Commit Buttons (optional - commonly used)
Commit buttons are simple buttons in the footer of the task dialog. Standard (English) terms include:
* OK
* Cancel
* Yes
* No
* Retry
* Close
It is possible to use custom text on commit buttons, but that is not recommended.
Notes on proper usage of each of the primary button types:
* The OK button should only be used in situations where a task dialog poses a question that can be answered by OK.
* The Cancel button should only be used when a task can truly be canceled, meaning the action that triggered the task dialog will be aborted and no change will be committed. It can be used in combination with other commit buttons or command links.
* The Yes & No button(s) should always be used in combination, and the text in the main instructions and / or main content should end in a yes / no question.
* The Retry button must appear with at least a Cancel button as an alternate option, so a user can choose not to retry.
* The Close button is used on any purely informational task dialog; i.e. where the user has no action to choose, but can just read the text and close the dialog.Previously the OK button was often used on such dialogs. It _should not_ be used in task dialogs for this purpose.
The following are some examples of how commit buttons should be used:
* See Figure 226 for an example of a Cancel button with command links
* See Figure 224 for an example of a purely informative task dialog with a close button
* See Figure 227 for an example of a task dialog with OK and Cancel buttons
### Default button or link
All tasks dialogs should have a default button or link explicitly assigned. If the task dialog contains an OK button, it should be the default.
Note: The exception is custom task dialogs with command links, which have actions that are equally viable, with none being "better" than the other, should not get assigned a default choice. All dialogs using only commit buttons must be assigned a default button.
## Navigation
### Tabs
Use when there are loosely related, yet distinct "chunks" of information need to exist within the same UI, but there is not enough room to display it all in a clear manner.
Separate the UI into distinct modal zones, each one represented by a "tab" with a descriptive label. The entire dialog should be treated as a single window with a single set of Commit buttons.
* All of the tabs should be visible at the same time
* Never have a single tab in a static UI such as dialog. Instead, use the tab's title for the page or dialog. Exception: if the number of tabs grows dynamically and the default is one. e.g., Excel's open workbook tabs
* Tabs are for navigation only. Selecting a tab should not perform any other action (such as a commit) besides simply switching to that page in the window
* Avoid nesting tabs within tabbed windows. In this case consider launching a child window
* Do not change the label on a tab dynamically based on interaction within the parent window
## Variations
### Variation A: Horizontal Tabs
**Figure 231 - Horizontal Tabs**
Avoid more than one row of horizontal tabs. If a second row is needed, consider a vertical tab.
### Variation B: Vertical Tabs
**Figure 232 - Vertical Tabs**
Vertical tabs are useful:
* In the Left-to-right Layout Flow
* If there are enough tabs that would force a second row in a horizontal layout
## Keyboard Accessibility
### Tab Order
Pressing the tab key cycles the focus between each editable control in the dialog. The general rule is left-to-right, top-to-bottom.
1. The default tab stop is at the control at the topmost, leftmost position in the dialog
2. Move right until there are no more controls in the current row
3. Move to the next row and start from the left-most control, moving right
4. Repeat step 2 until there are no more rows. Always end with the OK/Cancel/Apply row
* Right and left arrow, down and up arrows, Tab and Shift-tab all have the same behavior, respectively. Except for when the focus is on the following:
* List control or combo box: The right/left, down/up arrows move the cursor down/up the list, respectively
* Grid control: The right/left move the cursor right/left across columns, And down/up arrows move cursor down/up the list, respectively
* Slider: The right/left, down/up arrows move the slider right/left, respectively
* Spinner: The right/left, down/up arrows move the spinner down/up, respectively
* Treat each Group conceptually as a nested dialog, following the above rules within each Group first and moving from the top-left Group, moving to the right until no more groups are encountered and then moving to the next row of Groups.
* If dialog is tabbed, default tab stop should be the default tab.
Tip: Visual Studio can assist with the creation and editing of tab order by toggling the Tab Order visual helper (accessed from the View Tab Order menu.)
### Access Keys
* Each editable control on a dialog should get a unique access key letter (which is represented by an underlined letter in the control's label)
* The user presses Alt key plus the assigned key and that control is activated as if it was clicked
* The default button does not require an access key since Enter is mapped to it
* The Cancel or Close button also does not need access key since Esc is mapped to it.
### Show More Button
Following the principle of [Progressive Disclosure](./Revit_API_Revit_API_Developers_Guide_Appendices_API_User_Interface_Guidelines_Progressive_Disclosure_html.html), users may need a way of showing more data than is presented as a default in the user interface. The Show More button is typically implemented in one of two ways:
_Expander Button_ : Provide a button with a label such as " < Preview " or "Show more > " The double brackets > should point towards where the new information pane will be presented. When opened, the double brackets should switch to indicate how the additional pane will be "closed."
See Figure 207 - Materials dialog from Revit for an example.
_Dialog Launcher_ : A button with ellipses (…) that launches a separate dialog. This is typically used to provide a separate UI for editing a selected item.
**Figure 233 -Dialog launcher button, as implemented in the Revit View Filters dialog**
## Committing Changes
Modal dialogs are used to make changes to data within the project file. Use when there is an editor a series of edits have been queued up in a modal dialog or form and need to be committed at once. If the dialog is purely informational in nature, use a Task Dialog, which has its own committing rules.
Each modal dialog or web-form must have a set of commit buttons for committing the changes and/or canceling the task and/or closing the dialog.
## Sizing
**Figure 234 - Commit Button sizes (taken from Microsoft Windows User Experience Guidelines)**
## Layout
A summary of commit button styles for different window types
**Pattern** | **Commit Button style**
---|---
Modal Dialog | OK/Cancel or [Action]/Cancel
Modeless dialog | Close button on dialog box and title bar
Progress Indicator | Use Cancel if returns the environment to its previous state (leaving no side effect); otherwise, use Stop
Commit buttons should follow this layout pattern.
**Figure 235 - Standard Commit Button layouts**
| **Button Type**
---|---
1 | Default (OK and other Action) buttons
2 | Cancel or Close Button
3 | Apply Button
4 | Dialog buttons (optional)
Position the Default, Cancel, and Apply button(s) in this order and right aligned. The Dialog button(s) (if present) are aligned to the left, but to the right of the help button (if present).
## Default (OK and other Action) buttons
The dialog must have a default action button. This button should be closely mapped to the primary task of the dialog. This can either be labeled OK or a more descriptive verb that describes the action.
* Make the button with less destructive result to be the Default button
* Enter key is the keyboard access point for the Default button
## OK button
OK buttons can be used when saving a setting or series of settings. OK button rules:
* OK button should be used when it is the ONLY action (besides cancel) that can be committed from the dialog. Do not mix OK with other action buttons
* In modal dialogs, clicking OK means apply the values, perform the task, and close the window Do not use OK buttons to respond to questions
* Label OK buttons correctly. The OK button should be labeled OK, not Ok or Okay
* Do not use OK buttons in modeless dialog boxes. Use a action button or Close button
*
## Action buttons
Action buttons have descriptive verbs that will be defined by the designer. Action button rules:
* Action buttons can be used to describe more clearly the action that will be taken when clicked
* One action button must be set as the default. This should be the action most closely mapped to the primary task of the dialog
* There can be one or more action buttons, but do not mix OK button with action buttons
* Use Cancel or Close button for negative commit buttons instead of specific responses to the main instruction
* Otherwise, if user wants to cancel, the negative commit would require more thinking than needed for this particular small task
## Cancel or Close Button
* Verify the Close button on the title bar has the same effect as Close or Cancel
* Esc is the keyboard shortcut for Cancel or Close
## Cancel button
* Cancel button should only be used when a task will be aborted and no change will be committed
* Clicking the Cancel button means abandon all changes, cancel the task, close the window, and return the environment to its previous state and leaving no side effect
* For nested choice dialog boxes, clicking the Cancel button in the owner choice dialog typically means any changes made by owned choice dialogs are also abandoned.
* Don't use Cancel button in modeless dialog boxes. Use Close button instead
## Close Button
* Use Close button for modeless dialog boxes, as well as modal dialogs that cannot be canceled
* Clicking Close button means close the dialog box window, leaving any existing side effects
## Apply button (optional)
Apply button will commit any changes made within the dialog on all tabs, pages, or levels within a hierarchy without closing the dialog. Optimally, the user will receive visual feedback of the applied changes. Here are some basic Apply Button rules:
* In modal or modeless dialogs, clicking Apply means apply the values, perform the task, and do not close the window
* In modeless dialog use Apply button only on those tasks that require significant or unknown upfront time to be performed, otherwise data change should be applied immediately
* The Apply button is disabled when no changes have been made. It becomes enabled when changes have been made
* Clicking cancel will NOT undo any changes that have been already committed with the Apply button
* Interacting with a child dialog (such as a confirmation) should not cause the Apply function to become enabled
* Clicking the Apply button after committing a child dialog (such as a confirmation message) will apply all the changes made previous to the action triggering the confirmation
## Dialog Button (optional)
A dialog button performs an action on the dialog itself. Examples include: Reset and Tools for managing Favorites in an Open Dialog. They should be aligned to the far left of the dialog (to the right of the help button if present) and should never be the default.
## Implementation Notes
* Keyboard Access - each commit button should have a keyboard access key mapped to it. The default button should be mapped to Enter
* The close button (whether it is Cancel or Close) should be mapped to Esc
* If Apply exists, and is NOT the default button, it should be mapped to Alt-A
**Parent page:** [API User Interface Guidelines](../Revit_API_Revit_API_Developers_Guide_Appendices_API_User_Interface_Guidelines_html.html)

View File

@@ -0,0 +1,14 @@
# Good Defaults
# Good Defaults
When a user needs to edit data or change a setting, the lack of any or obvious default can lead to errors and force users to re-edit and re-enter information. Remember to:
* Set the control value with a reasonable default value for the current context by consulting usage data or using the previously entered values by the user. The appropriate default may be blank.
* Where appropriate, remember the last used setting of the user instead of always presenting the same system default.
A common example is pre-setting certain settings or options which would be the most often selected.
**Parent page:** [API User Interface Guidelines](../Revit_API_Revit_API_Developers_Guide_Appendices_API_User_Interface_Guidelines_html.html)

View File

@@ -0,0 +1,13 @@
# Good Layout
# Good Layout
A well-balanced layout of information can be achieved by following Gestalt Principles:
* Proximity: items placed close together are perceived as being closely associated
* Similarity: items that share similar appearance are perceived as being closely associated
* Continuity: humans tend to prefer simple, unbroken contours over more complex, yet similarly plausible forms
**Parent page:** [API User Interface Guidelines](../Revit_API_Revit_API_Developers_Guide_Appendices_API_User_Interface_Guidelines_html.html)

View File

@@ -0,0 +1,7 @@
# Introduction
# Introduction
This section is intended to provide guidance and best practices for designing user interfaces for applications based on the Revit API. The following principles are followed by the Autodesk design and development staff when developing Revit and will provide a good starting point to the rest of this document.
**Parent page:** [API User Interface Guidelines](../Revit_API_Revit_API_Developers_Guide_Appendices_API_User_Interface_Guidelines_html.html)

View File

@@ -0,0 +1,35 @@
# Localization of the User Interface
# Localization of the User Interface
If you plan to localize the user interface into languages other than English, be aware of the space requirements.
The English language is very compact, so translated text usually ends up taking up more space (30% on average for longer strings, 100% or more on short strings (a word or short phrase)). This can present problems if translated text is inserted into dialog boxes that were designed for an English product, because there is not usually sufficient space in available to fit the translated text. The common solution to this problem is to resize the dialog box so that the translated text fits properly, but most times this isn't the best solution.
Instead, by careful design of the dialog box by the developer, the same dialog box resource can be used for most if not all languages without the need for costly and time-consuming re-engineering. This paper tells you how to design 'global' dialog boxes.
These following design rules must be adhered to at all times to prevent globalization and localization problems.
* The English dialog must be at least 30% smaller than the minimum screen size specified by the product.
* A dialog must be designed with the following amounts of expansion in mind. This amount of extra space should look good in English and avoid resizing for most localization.
<table cellpadding="4" cellspacing="0" summary="" class="table" frame="border" border="1" rules="all">
**CHARACTERS** | **PERCENTAGE**
1-5 characters | 100%
6-10 characters | 40%
11-100 characters | 30%
100 characters or greater | 20%
* Make the invisible control frame around text controls, frames etc. as large as possible to allow for longer translated text. These frames should be at least 30% larger than the English text.
Refer to the [Microsoft's guidelines on localization](https://learn.microsoft.com/en-us/dotnet/core/extensions/localization) for additional information regarding localizing text.
**Parent page:** [API User Interface Guidelines](../Revit_API_Revit_API_Developers_Guide_Appendices_API_User_Interface_Guidelines_html.html)

View File

@@ -0,0 +1,26 @@
# Progressive Disclosure
# Progressive Disclosure
As an application's complexity increases, it becomes harder for the user to find what they need. To accommodate the complexity of a user interface, it is common to separate the data or options into groupings. The concept of Progressive Disclosure shows the needed information as necessary. Progressive Disclosure may be user-initiated, system initiated, or a hybrid of the two.
### User initiated action
Examples here include a Show More button for launching a child dialog, Tabs for chunking interface elements into logical chunks, and a Collection Search/Filter for selectively displaying items in a collection by certain criteria.
### System initiated action
These can either be:
* Event based: An event within the product initiates the disclosure of more information, such as with a Task Dialog.
* Time based: More information is disclosed after specified amount of time passes, such as in an automatic slide show.
### Hybrid (user and time initiated)
An example of a hybrid is Progressive Filter, where the user initiates the initial tooltip by hovering the mouse over the control, but after a set amount of time a more detailed tooltip appears.
**Parent page:** [API User Interface Guidelines](../Revit_API_Revit_API_Developers_Guide_Appendices_API_User_Interface_Guidelines_html.html)

View File

@@ -0,0 +1,224 @@
# Ribbon Guidelines
# Ribbon Guidelines
The following are aspects of the ribbon UI that can be modified by individual API developers. These guidelines must be followed to make your application's user interface (UI) compliant with standards used by Autodesk.
## Ribbon Tab Placement
To make more room on the ribbon, third-party applications can now add ribbon controls to the Analyze tab as well as the Add-Ins tab.
* Applications that add and/or modify elements within Revit should be added to the Add-Ins tab.
* Applications that analyze existing data within the Revit model should be added to the Analyze tab.
* Applications MUST NOT be added to both the Add-Ins and Analyze tabs.
### Contextual Tab Focus User Option
The Revit 2012 product line contains a user option (located on the User Interface tab of the Options dialog) which allows users to choose whether or not to automatically switch to a contextual tab upon selection. This option is set to automatically switch by default. For some API applications, it may be favorable to have this option disabled, to prevent users from being switched away from the Add-ins or Analyze tab. In these cases, it is best to inform users of this option in the documentation and/or as informational text in the installer user interface.
### Number of Panels per Tab
Each API application SHOULD add only one panel to either the Add-Ins tab.
### Panel Layout
The following guidelines define the proper way to lay out a panel on the Add-ins tab. The following panel under General Layout provides an example to follow.
### General layout
**Figure 236 - Room & Area panel in the 2011 Revit products**
A panel SHOULD have a large button as the left-most control. This button SHOULD be the most commonly accessed command in the application. The left-most button icon will represent the entire panel when it collapses (see Panel Resizing and Collapsing below.) This button MAY be the only button in the group, or this button MAY be followed by a large button and/or a small button stack.
Panels SHOULD NOT exceed three columns. If more controls are necessary, use a drop-down button.
Panels SHOULD only contain controls for launching commands and controlling the application. Controls for managing settings or launching help and "about this application" should be located in a Slide-out Panel.
### Small button stack
* The stack MUST have at least two buttons and MUST NOT exceed three.
* The order of the small buttons SHOULD follow most frequent on bottom to least frequent on top. This is because the more frequently accessed command should be closer to the modeling window.
### Panel Resizing and Collapsing
By default, panels will be placed left to right in descending order left to right based on the order in which they were installed by the customer. Once the width of the combined panels exceeds the width of the current window, the panels will start to resize starting from the right in the following order:
1. Panels with large buttons:
1. Small buttons lose their labels, then:
2. The panel collapses to a single large button (the icon representing the panel will be the first icon on the left.)
2. Panels with ONLY small button stack(s):
1. Small buttons lose their labels and the panel label gets truncated to four characters and an ellipsis (three periods in a row.)
2. If a small button stack is the left-most control in a panel, then the top button must have a large icon associated with it. This icon will represent the panel when collapsed.
The About button/link should be located within the main user interface and not on a ribbon panel.
Note: Panel resizing and collapsing is handled automatically by the ribbon component.
### Ribbon Controls
#### Ribbon button
A Ribbon button is the most basic and most frequently-used control. Pressing a button invokes a command.
Ribbon buttons can be one of the three sizes:
* Large: MUST have a text label
* Medium: MAY have a text label
* Small: MAY have a text label
#### Radio Buttons
A radio button group represents a set of controls that are mutually exclusive; only one can be chosen at a time. These groups can be stacked horizontally (as seen in the justification buttons in the example below.)
**Figure 237 - The Format text panel from Revit 2011**
#### Drop-down button
* The top label SHOULD sufficiently describe the contents of the drop-down list.
* Every item in the list SHOULD contain a large icon.
* A horizontal separator can be optionally added between controls. This should be used if the items are logically grouped under one button, but are separated into distinct groups.
**Figure 238 - Floor drop-down button in Revit**
#### Split Button
A split button is a drop-down button with a default command that can be accessed by pressing the left side of the button. The right side of the button, separated by a small vertical separator, opens a drop-down list. The default command SHOULD be duplicated with the top command in the list.
A split button's default command can be _synchronized_. That is, the default command changes depending on the last used command in the drop-down list.
#### Combo Box and Text Box
The guidelines for combo boxes and text boxes in the ribbon are the same for those used within dialogs. See the [Dialog Controls](Revit_API_Revit_API_Developers_Guide_Appendices_API_User_Interface_Guidelines_Dialog_Guidelines_html.html) section.
#### Slide-out Panel
**Figure 239 - Room & Area slide-out panel in Revit**
In general slide-outs should be used for commands relevant to the panel, but not primary or commonly used ones.
Each open panel can be optionally pinned open. Otherwise, once the mouse leaves the panel, it closes by itself.
Three suggested uses of slide outs are commands that launch settings dialogs related to the panel's task(s), a Help button, and an About button.
#### Vertical separator
A vertical separator MAY be added between a control or sets of controls to create distinct groupings of commands within a panel. A panel SHOULD have no more than two separators.
#### Icons
For proper icon design, see the icon design guidelines.
### Text Usage
#### Button Labels
These guidelines are for English language only.
* MUST not have any punctuation (except hyphen, ampersand or forward slash)
* MUST be no longer than three words
* MUST be no longer than 36 characters
* MUST be Title Case; e.g., Show Mass
* The ampersand "&" MUST be used instead of "and". A space should appear before and after the ampersand
* The forward slash "/" MUST be used instead of "or". No spaces should appear before and after the slash
* Only large buttons MAY have two line labels but MUST NOT have more than two lines. Labels for all other controls MUST fit on a single line
* Button labels MUST NOT contain ellipses ()
* Every word MUST be in capital case except articles ("a," "an," and "the"), coordinating conjunctions (for example, "and," "or," "but," "so," "yet," "with," and "nor"), and prepositions with fewer than four letters (like "in"). The first and last words are always capitalized
#### Panel Labels
These guidelines are English-only. All rules from the Command Labels section apply to Panel Labels in addition to the following:
* The name of the panel SHOULD be specific. Vague, non-descriptive and unspecific terms used to describe panel content will reduce the label's usefulness
* Applications MUST NOT use panel names that use the abbreviations "misc." or "etc"
* Panel labels SHOULD NOT include the term "add-ins" since it is redundant with the tab label
* Panel labels MAY include the name of the third party product or provider
### Tooltips
The following are guidelines for writing tooltip text. Write concisely. There is limited space to work with.
#### Localization Considerations
* Make every word count. This is particularly important for localizing tooltip text to other languages
* Do not use gerunds (verb forms used as nouns) because they can be confused with participles (verb forms used as adjectives). In the example, "Drawing controls", drawing could be used as a verb or a noun. A better example is "Controls for drawing"
* Do not include lengthy step-by-step procedures in tooltips. These belong in Help
* Use terminology consistently
* Make sure that your use of conjunctions does not introduce ambiguities in relationships. For example, instead of saying "replace and tighten the hinges", it would be better to split the conjunction up into two simple (and redundant) sentences - "Replace the hinges. Then tighten the hinges"
* Be careful with "helping" verbs. Examples of helping verbs include shall, may, would have, should have, might have, and can. For example, can and may could be translated as "capability" and "possibility" respectively
* Watch for invisible plurals such as "object and attribute settings". Does this mean "the settings for one object and one attribute" or "the settings for many objects and many attributes"?
* Be cautious about words that can be either nouns or verbs. Use articles or rewrite phrases like "Model Display" where model can be a noun or a verb in our software. Another example is "empty file". It can mean "to empty a file" or "a file with no content"
* Be careful using metaphors. Metaphors can be subtle and are often discussed in the context of icons that are not culturally appropriate or understood across cultures. Text metaphors (such as "places the computer in a hibernating state") can also be an issue. Instead, you might say "places the computer in a low-power state"
#### Writing/Wording Considerations
* Use simple sentences. The "Verb-Object-Adverb" format is recommended
* Use strong and specific verbs that describe a specific action (such as "tile") rather than weak verbs (such as "use to…")
* Write in the active voice (for example, "Moves objects between model space and paper space")
* Use the descriptive style instead of the imperative style ("Opens an existing drawing file" vs. "Open an existing drawing file")
* Make the tooltip description easily recognizable by using the third person singular (for example - "Specifies the current color" instead of "Specify the current color")
* Don't use slang, jargon, or hard to understand acronyms
#### Formatting Considerations
* Use only one space between sentences.
* Avoid repetitive text. The content in the tooltip should be unique and add value.
* Focus on the quality and understandability of the tooltip. Is the description clear? Is it helpful?
* Unless it's a system variable or command, do not use bold. Although bold is supported in Asian languages, it is strongly recommended to avoid using bold and italics, because of readability and stylistic issues.
* Avoid Dabbreviations. For example, the word "Number" has many common abbreviations: No., Nbr, Num, Numb. It is best to spell out terms.
**Good Example:**
An example of a more useful descriptive sentence might be "Adds a file such as a .bmp or .png". This provides more detailed information and gives the user more insight into the feature.
**Poor Example:**
In this example, the tooltip content repeats the tooltip title verbatim and does not add value to the tooltip. Additionally, if the translator cannot identify whether this string is a name/title or a descriptive sentence, it will be difficult for them to decide on the translation style.
As with other guideline issues, follow [Microsoft Guidelines for title and sentence case](https://docs.microsoft.com/en-us/style-guide/capitalization) (listed below):
#### Title Case
* Capitalize all nouns, verbs (including is and other forms of to be), adverbs (including than and when), adjectives (including this and that), and pronouns (including its)
* Capitalize the first and last words, regardless of their parts of speech (for example, The Text to Look For)
* Capitalize prepositions that are part of a verb phrase (for example, Backing Up Your Disk)
* Do not capitalize articles (a, an, the), unless the article is the first word in the title
* Do not capitalize coordinate conjunctions (and, but, for, nor, or), unless the conjunction is the first word in the title
* Do not capitalize prepositions of four or fewer letters, unless the preposition is the first word in the title
* Do not capitalize to in an infinitive phrase (for example, How to Format Your Hard Disk), unless the phrase is the first word in the title
* Capitalize the second word in compound words if it is a noun or proper adjective, an "e-word," or the words have equal weight (for example, E-Commerce, Cross-Reference, Pre-Microsoft Software, Read/Write Access, Run-Time). Do not capitalize the second word if it is another part of speech, such as a preposition or other minor word (for example, Add-in, How-to, Take-off)
* Capitalize user interface and application programming interface terms that you would not ordinarily capitalize, unless they are case-sensitive (for example, The fdisk command)
* Follow the traditional capitalization of keywords and other special terms in programming languages (for example, The printf function, Using the EVEN and ALIGN Directives)
* Capitalize only the first word of each column heading
#### Sentence Case
* Always capitalize the first word of a new sentence
* Do not capitalize the word following a colon unless the word is a proper noun, or the text following the colon is a complete sentence
* Do not capitalize the word following an em-dash unless it is a proper noun, even if the text following the dash is a complete sentence
* Always capitalize the first word of a new sentence following any end punctuation. Rewrite sentences that start with a case-sensitive lowercase word
**Parent page:** [API User Interface Guidelines](../Revit_API_Revit_API_Developers_Guide_Appendices_API_User_Interface_Guidelines_html.html)

View File

@@ -0,0 +1,9 @@
# Speak the Users' Language
# Speak the Users' Language
Understanding and communicating within the user's language is always critical, but particularly within a user interface. Users will need to provide as well as receive feedback from the application.
The tone used in user interface language should be informal, helpful, and consultative in tone. The user interface should politely provide information that is clear and informative to the user, and that can be acted upon accordingly with confidence.
**Parent page:** [API User Interface Guidelines](../Revit_API_Revit_API_Developers_Guide_Appendices_API_User_Interface_Guidelines_html.html)

View File

@@ -0,0 +1,15 @@
# Terminology Definitions
# Terminology Definitions
Several words are used to signify the requirements of the standards. These words are capitalized. This section defines how these special words should be interpreted. The interpretation has been copied from [Internet Engineering Task Force RFC 2119](http://www.ietf.org/rfc/rfc2119.txt).
**WORD** | **DEFINITION**
---|---
**_MUST_** | This word or the term "SHALL", mean that the item is an absolute requirement
**_MUST NOT_** | This phrase, or the phrase "SHALL NOT", means that the item is an absolute prohibition
**_SHOULD_** | This word, or the adjective "RECOMMENDED", mean that there may exist valid reasons in particular circumstances to ignore the item, but the full implications must be understood and carefully weighed before choosing a different course
**_SHOULD NOT_** | This phrase, or the phrase "NOT RECOMMENDED", mean that there may exist valid reasons in particular circumstances when the particular behavior is acceptable or even useful, but the full implications should be understood and the case carefully weighed before implementing any behavior described with this label
**_MAY_** | This word, or the adjective "OPTIONAL", means that the item is truly optional. One product team may choose to include the item because a particular type of user requires it or because the product team feels that it enhances the product while another product team may omit the same item
**Parent page:** [API User Interface Guidelines](../Revit_API_Revit_API_Developers_Guide_Appendices_API_User_Interface_Guidelines_html.html)

View File

@@ -0,0 +1,21 @@
# API User Interface Guidelines
# API User Interface Guidelines
**Pages in this section**
* [Introduction](API_User_Interface_Guidelines/Revit_API_Revit_API_Developers_Guide_Appendices_API_User_Interface_Guidelines_Introduction_html.html)
* [Consistency](API_User_Interface_Guidelines/Revit_API_Revit_API_Developers_Guide_Appendices_API_User_Interface_Guidelines_Consistency_html.html)
* [Speak the Users' Language](API_User_Interface_Guidelines/Revit_API_Revit_API_Developers_Guide_Appendices_API_User_Interface_Guidelines_Speak_the_Users_Language_html.html)
* [Good Layout](API_User_Interface_Guidelines/Revit_API_Revit_API_Developers_Guide_Appendices_API_User_Interface_Guidelines_Good_Layout_html.html)
* [Good Defaults](API_User_Interface_Guidelines/Revit_API_Revit_API_Developers_Guide_Appendices_API_User_Interface_Guidelines_Good_Defaults_html.html)
* [Progressive Disclosure](API_User_Interface_Guidelines/Revit_API_Revit_API_Developers_Guide_Appendices_API_User_Interface_Guidelines_Progressive_Disclosure_html.html)
* [Localization of the User Interface](API_User_Interface_Guidelines/Revit_API_Revit_API_Developers_Guide_Appendices_API_User_Interface_Guidelines_Localization_of_the_User_Interface_html.html)
* [Dialog Guidelines](API_User_Interface_Guidelines/Revit_API_Revit_API_Developers_Guide_Appendices_API_User_Interface_Guidelines_Dialog_Guidelines_html.html)
* [Ribbon Guidelines](API_User_Interface_Guidelines/Revit_API_Revit_API_Developers_Guide_Appendices_API_User_Interface_Guidelines_Ribbon_Guidelines_html.html)
* [Common Definitions](API_User_Interface_Guidelines/Revit_API_Revit_API_Developers_Guide_Appendices_API_User_Interface_Guidelines_Common_Definitions_html.html)
* [Terminology Definitions](API_User_Interface_Guidelines/Revit_API_Revit_API_Developers_Guide_Appendices_API_User_Interface_Guidelines_Terminology_Definitions_html.html)
**Parent page:** [Appendices](../Revit_API_Revit_API_Developers_Guide_Appendices_html.html)

View File

@@ -0,0 +1,11 @@
# Concrete-Rectangular Beam
# Concrete-Rectangular Beam
**Figure 178: Concrete-Regangular Beam Parameters**
**Figure 179: Concrete-Rectangular Beam Cross Section**
**Figure 180: Concrete-Rectangular Beam**
**Parent page:** [Concrete Section Definitions](../Revit_API_Revit_API_Developers_Guide_Appendices_Concrete_Section_Definitions_html.html)

View File

@@ -0,0 +1,13 @@
# Precast-Double Tee
# Precast-Double Tee
**Figure 194: Precast-Double Tee**
**Figure 195: Precast-Double Tee Cross Section**
**Figure 196: Precast-Double Tee Cross Section 2**
**Figure 197: Precast-Double Tee**
**Parent page:** [Concrete Section Definitions](../Revit_API_Revit_API_Developers_Guide_Appendices_Concrete_Section_Definitions_html.html)

View File

@@ -0,0 +1,11 @@
# Precast-Inverted Tee
# Precast-Inverted Tee
**Figure 191: Precast-Inverted Tee Properties**
**Figure 192: : Precast-Inverted Tee Cross Section**
**Figure 193: Precast-Inverted Tee**
**Parent page:** [Concrete Section Definitions](../Revit_API_Revit_API_Developers_Guide_Appendices_Concrete_Section_Definitions_html.html)

View File

@@ -0,0 +1,11 @@
# Precast-L Shaped Beam
# Precast-L Shaped Beam
**Figure 184: Precast-L Shaped Beam Properties**
**Figure 185: Precast-L Shaped Beam Cross Section**
**Figure 186: Precast-L Shaped Beam**
**Parent page:** [Concrete Section Definitions](../Revit_API_Revit_API_Developers_Guide_Appendices_Concrete_Section_Definitions_html.html)

View File

@@ -0,0 +1,11 @@
# Precast-Rectangular Beam
# Precast-Rectangular Beam
**Figure 181: Precast-Rectangular Beam Properties**
**Figure 182: Precast-Rectangular Beam Cross Section**
**Figure 183: Precast-Rectangular Beam**
**Parent page:** [Concrete Section Definitions](../Revit_API_Revit_API_Developers_Guide_Appendices_Concrete_Section_Definitions_html.html)

View File

@@ -0,0 +1,13 @@
# Precast-Single Tee
# Precast-Single Tee
**Figure 187: Precast-Single Tee Properties**
**Figure 188: Precast-Single Tee Cross Section**
**Figure 189: Precast-Single Tee Cross Section 2**
**Figure 190: Precast-Single Tee**
**Parent page:** [Concrete Section Definitions](../Revit_API_Revit_API_Developers_Guide_Appendices_Concrete_Section_Definitions_html.html)

View File

@@ -0,0 +1,16 @@
# Concrete Section Definitions
# Concrete Section Definitions
**Pages in this section**
* [Concrete-Rectangular Beam](Concrete_Section_Definitions/Revit_API_Revit_API_Developers_Guide_Appendices_Concrete_Section_Definitions_Concrete_Rectangular_Beam_html.html)
* [Precast-Rectangular Beam](Concrete_Section_Definitions/Revit_API_Revit_API_Developers_Guide_Appendices_Concrete_Section_Definitions_Precast_Rectangular_Beam_html.html)
* [Precast-L Shaped Beam](Concrete_Section_Definitions/Revit_API_Revit_API_Developers_Guide_Appendices_Concrete_Section_Definitions_Precast_L_Shaped_Beam_html.html)
* [Precast-Single Tee](Concrete_Section_Definitions/Revit_API_Revit_API_Developers_Guide_Appendices_Concrete_Section_Definitions_Precast_Single_Tee_html.html)
* [Precast-Inverted Tee](Concrete_Section_Definitions/Revit_API_Revit_API_Developers_Guide_Appendices_Concrete_Section_Definitions_Precast_Inverted_Tee_html.html)
* [Precast-Double Tee](Concrete_Section_Definitions/Revit_API_Revit_API_Developers_Guide_Appendices_Concrete_Section_Definitions_Precast_Double_Tee_html.html)
**Parent page:** [Appendices](../Revit_API_Revit_API_Developers_Guide_Appendices_html.html)

View File

@@ -0,0 +1,7 @@
# Array
# Array
Arrays hold a series of data elements, usually of the same size and data type. Individual elements are accessed by their position in the array. The position is provided by an index, which is also called a subscript. The index usually uses a consecutive range of integers, but the index can have any ordinal set of values.
**Parent page:** [Glossary](../Revit_API_Revit_API_Developers_Guide_Appendices_Glossary_html.html)

View File

@@ -0,0 +1,7 @@
# BIM
# BIM
Building Information Modeling is the creation and use of coordinated, internally consistent, computable information about a building project in design and construction. In a BIM application the graphics are derived from the information and are not the original information itself like in general CAD applications.
**Parent page:** [Glossary](../Revit_API_Revit_API_Developers_Guide_Appendices_Glossary_html.html)

View File

@@ -0,0 +1,7 @@
# Class
# Class
In object-oriented programming (OOP), classes are used to group related Properties (variables) and Methods (functions) together. A typical class describes how those methods operate upon and manipulate the properties. Classes can be standalone or inherited from other classes. In the latter, a class from which others are derived is usually referred to as a Base Class.
**Parent page:** [Glossary](../Revit_API_Revit_API_Developers_Guide_Appendices_Glossary_html.html)

View File

@@ -0,0 +1,7 @@
# Element ID
# Element ID
Each element has a corresponding ID. It is identified by an integer value. It provides a way of uniquely identifying an Element within an Autodesk Revit project. It is only unique for one project, but not unique across separate Autodesk Revit projects.
**Parent page:** [Glossary](../Revit_API_Revit_API_Developers_Guide_Appendices_Glossary_html.html)

View File

@@ -0,0 +1,7 @@
# Element UID
# Element UID
Each element has a corresponding UID. It is a string identifier that is universally unique. That means it is unique across separate Autodesk Revit projects.
**Parent page:** [Glossary](../Revit_API_Revit_API_Developers_Guide_Appendices_Glossary_html.html)

View File

@@ -0,0 +1,7 @@
# Events
# Events
Events are messages or functions that are called when an event occurs within an application. For example when a model is saved or opened.
**Parent page:** [Glossary](../Revit_API_Revit_API_Developers_Guide_Appendices_Glossary_html.html)

View File

@@ -0,0 +1,7 @@
# Iterator
# Iterator
An iterator is an object that allows a programmer to traverse through all elements in a collection (an array, a set, etc.), regardless of its specific implementation.
**Parent page:** [Glossary](../Revit_API_Revit_API_Developers_Guide_Appendices_Glossary_html.html)

View File

@@ -0,0 +1,7 @@
# Method
# Method
A method is a function or procedure that belongs to a class and operates or accesses the class data members. In procedural programming, this is called a function.
**Parent page:** [Glossary](../Revit_API_Revit_API_Developers_Guide_Appendices_Glossary_html.html)

View File

@@ -0,0 +1,7 @@
# Namespace
# Namespace
A namespace is an organizational unit used to group similar and/or functionally related classes together.
**Parent page:** [Glossary](../Revit_API_Revit_API_Developers_Guide_Appendices_Glossary_html.html)

View File

@@ -0,0 +1,7 @@
# Overloading
# Overloading
Method overloading is when different methods (functions) of the same name are invoked with different types and/or numbers of parameters passed.
**Parent page:** [Glossary](../Revit_API_Revit_API_Developers_Guide_Appendices_Glossary_html.html)

View File

@@ -0,0 +1,11 @@
# Properties
# Properties
Properties are data members of a class accessible to the class user. They are also known as public members or variables.
Some properties are read only (support Get() method) and some are modifiable (support Set() method).
Example: "X" is a read-only property on the XYZ class. "Name" is a modifiable property on the Zone class.
**Parent page:** [Glossary](../Revit_API_Revit_API_Developers_Guide_Appendices_Glossary_html.html)

View File

@@ -0,0 +1,7 @@
# Revit Families
# Revit Families
A Family is a collection of objects called types. A family groups elements with a common set of parameters, identical use, and similar graphical representation. Different types in a family can have different values of some or all parameters, but the set of parameters - their names and their meaning - are the same.
**Parent page:** [Glossary](../Revit_API_Revit_API_Developers_Guide_Appendices_Glossary_html.html)

View File

@@ -0,0 +1,13 @@
# Revit Parameters
# Revit Parameters
There are a number of Revit parameter types.
* Shared Parameters can be thought of as user-defined variables.
* System Parameters are variables that are hard-coded in Revit.
* Family parameters are variables that are defined when a family is created or modified.
**Parent page:** [Glossary](../Revit_API_Revit_API_Developers_Guide_Appendices_Glossary_html.html)

View File

@@ -0,0 +1,7 @@
# Revit Types
# Revit Types
A Type is a member of a Family. Each Type has specific parameters that are constant for all instances of the Type that exist in your model; these are called Type Properties. Types have other parameters called Instance parameters, which can vary in your model.
**Parent page:** [Glossary](../Revit_API_Revit_API_Developers_Guide_Appendices_Glossary_html.html)

View File

@@ -0,0 +1,7 @@
# Sets
# Sets
A set is a collection (container) of values without a particular order and no repeated values. It corresponds with the mathematical concept of set except for the restriction that it has to be finite.
**Parent page:** [Glossary](../Revit_API_Revit_API_Developers_Guide_Appendices_Glossary_html.html)

View File

@@ -0,0 +1,25 @@
# Glossary
# Glossary
**Pages in this section**
* [Array](Glossary/Revit_API_Revit_API_Developers_Guide_Appendices_Glossary_Array_html.html)
* [BIM](Glossary/Revit_API_Revit_API_Developers_Guide_Appendices_Glossary_BIM_html.html)
* [Class](Glossary/Revit_API_Revit_API_Developers_Guide_Appendices_Glossary_Class_html.html)
* [Events](Glossary/Revit_API_Revit_API_Developers_Guide_Appendices_Glossary_Events_html.html)
* [Iterator](Glossary/Revit_API_Revit_API_Developers_Guide_Appendices_Glossary_Iterator_html.html)
* [Method](Glossary/Revit_API_Revit_API_Developers_Guide_Appendices_Glossary_Method_html.html)
* [Namespace](Glossary/Revit_API_Revit_API_Developers_Guide_Appendices_Glossary_Namespace_html.html)
* [Overloading](Glossary/Revit_API_Revit_API_Developers_Guide_Appendices_Glossary_Overloading_html.html)
* [Properties](Glossary/Revit_API_Revit_API_Developers_Guide_Appendices_Glossary_Properties_html.html)
* [Revit Families](Glossary/Revit_API_Revit_API_Developers_Guide_Appendices_Glossary_Revit_Families_html.html)
* [Revit Parameters](Glossary/Revit_API_Revit_API_Developers_Guide_Appendices_Glossary_Revit_Parameters_html.html)
* [Revit Types](Glossary/Revit_API_Revit_API_Developers_Guide_Appendices_Glossary_Revit_Types_html.html)
* [Sets](Glossary/Revit_API_Revit_API_Developers_Guide_Appendices_Glossary_Sets_html.html)
* [Element ID](Glossary/Revit_API_Revit_API_Developers_Guide_Appendices_Glossary_Element_ID_html.html)
* [Element UID](Glossary/Revit_API_Revit_API_Developers_Guide_Appendices_Glossary_Element_UID_html.html)
**Parent page:** [Appendices](../Revit_API_Revit_API_Developers_Guide_Appendices_html.html)

View File

@@ -0,0 +1,29 @@
# Add Code
# Add Code
Remove the existing code and add the following code to create the add-in. When writing the code in VB.NET, you must pay attention to key letter capitalization.
**Code Region 30-9: Hello World in VB.NET**
---
Imports System
Imports Autodesk.Revit.UI
Imports Autodesk.Revit.DB
<Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.ReadOnly)> _
Public Class HelloWorld
Implements IExternalCommand
Public Function Execute(ByVal revit As ExternalCommandData, ByRef message As String, _
ByVal elements As ElementSet) As Autodesk.Revit.UI.Result _
Implements IExternalCommand.Execute
TaskDialog.Show("Revit", "Hello World")
Return Autodesk.Revit.UI.Result.Succeeded
End Function
End Class
**Parent page:** [Hello World for VB.NET](../Revit_API_Revit_API_Developers_Guide_Appendices_Hello_World_for_VB_NET_html.html)

View File

@@ -0,0 +1,28 @@
# Add Reference and Namespace
# Add Reference and Namespace
VB.NET uses a process similar to C#. After you create the Hello World project, complete the following steps:
1. Right-click on Dependencies under the project name in the Solution Explorer to display a context menu.
2. From the context menu, select Add Project Reference to open the Reference Manager dialog box. **Figure: Reference Manager**
3. In the Reference Manager dialog box, click the Browse tab, then click the Browse button.
4. Locate the folder where Revit is installed and click the RevitAPI.dll. For example, the installed folder location might be C:\Program Files\Autodesk\Revit2026.
5. Click OK to add the reference.
6. Repeat steps above to add a reference to RevitAPIUI.dll, which is in the same folder as Revit API.dll.
**Figure: Add references**
7. Click OK to close the Reference Manager dialog.
8. To complete the process, click RevitAPI under References in the Solution Explorer. Set Copy Local to `No` in the Properties frame. Repeat for RevitAPIUI.
**Parent page:** [Hello World for VB.NET](../Revit_API_Revit_API_Developers_Guide_Appendices_Hello_World_for_VB_NET_html.html)

View File

@@ -0,0 +1,7 @@
# Build the Program
# Build the Program
After completing the code, you must build the file. From the Build menu, click Build Solution. Output from the build appears in the Output window indicating that the project compiled without errors.
**Parent page:** [Hello World for VB.NET](../Revit_API_Revit_API_Developers_Guide_Appendices_Hello_World_for_VB_NET_html.html)

View File

@@ -0,0 +1,20 @@
# Change the Class Name
# Change the Class Name
To change the class name, complete the following steps:
1. In the Solution Explorer, right-click Class1.vb to display a context menu.
2. From the context menu, select Rename. Rename the file HelloWorld.vb.
3\. The following message will appear. Click Yes.
**Figure 174: Change the class name**
4. In the Solution Explorer, double-click HelloWorld.vb to open it for editing.
**Parent page:** [Hello World for VB.NET](../Revit_API_Revit_API_Developers_Guide_Appendices_Hello_World_for_VB_NET_html.html)

Some files were not shown because too many files have changed in this diff Show More