The ScheduleDefinition class helps define the ViewSchedule.
The ScheduleDefinition class contains various settings related to the contents of a schedule view, including:
Most schedules contain a single ScheduleDefinition which is retrieved via the ViewSchedule.Definition property. In Revit MEP, schedules of certain categories can contain an "embedded schedule" containing elements associated with the elements in the primary schedule, for example a room schedule showing the elements inside each room or a duct system schedule showing the elements associated with each system. An embedded schedule has its own category, fields, filters, etc. Those settings are stored in a second ScheduleDefinition object. When present, the embedded ScheduleDefinition is obtained from the ScheduleDefinition.EmbeddedDefinition property.
Once a ViewSchedule is created, fields can be added. The ScheduleDefinition.GetSchedulableFields() method will return a list of SchedulableField objects representing the non-calculated fields that may be included in the schedule. A new field can be added from a SchedulableField object or using a ScheduleFieldType. The following table describes the options available from the ScheduleFieldType enumeration.
Member name | Description |
Instance | An instance parameter of the scheduled elements. All shared parameters also use this type, regardless of whether they are instance or type parameters. |
ElementType | A type parameter of the scheduled elements. |
Count | The number of elements appearing on the schedule row. |
ViewBased |
A specialized type of field used for a few parameters whose displayed values can change based on the settings of the view:
|
Formula | A formula calculated from the values of other fields in the schedule. |
Percentage | A value indicating what percent of the total of another field each element represents. |
Room | A parameter of the room that a scheduled element belongs to. |
FromRoom | A parameter of the room on the "from" side of a door or window. |
ToRoom | A parameter of the room on the "to" side of a door or window. |
ProjectInfo | A parameter of the Project Info element in the project that the scheduled element belongs to, which may be a linked file. Only allowed in schedules that include elements from linked files. |
Material | In a material takeoff, a parameter of one of the materials of a scheduled element. |
MaterialQuantity | In a material takeoff, a value representing how a particular material is used within a scheduled element. The parameter ID can be MATERIAL_AREA, MATERIAL_VOLUME, or MATERIAL_ASPAINT. |
RevitLinkInstance | A parameter of the RevitLinkInstance that an element in a linked file belongs to. Currently RVT_LINK_INSTANCE_NAME is the only supported parameter. Only allowed in schedules that include elements from linked files. |
RevitLinkType | A parameter of the RevitLinkType that an element in a linked file belongs to. Currently RVT_LINK_FILE_NAME_WITHOUT_EXT is the only supported parameter. Only allowed in schedules that include elements from linked files. |
StructuralMaterial | A parameter of the structural material of a scheduled element. |
Space | A parameter of the space that a scheduled element belongs to. |
Using one of the ScheduleDefinition.AddField() methods will add the field to the end of the field list. To place a new field in a specific location in the field list, use one of the ScheduleDefinition.InsertField() methods. Fields can also be ordered after the fact using ScheduleDefinition.SetFieldOrder().
The following is a simple example showing how to add fields to a view if they are not already in the view schedule.
Code Region: Adding fields to a schedule |
/// <summary> /// Add fields to view schedule. /// </summary> /// <param name="schedules">List of view schedule.</param> public void AddFieldToSchedule(List<ViewSchedule> schedules) { IList<SchedulableField> schedulableFields = null; foreach (ViewSchedule vs in schedules) { //Get all schedulable fields from view schedule definition. schedulableFields = vs.Definition.GetSchedulableFields(); foreach (SchedulableField sf in schedulableFields) { bool fieldAlreadyAdded = false; //Get all schedule field ids IList<ScheduleFieldId> ids = vs.Definition.GetFieldOrder(); foreach (ScheduleFieldId id in ids) { //If the GetSchedulableField() method of gotten schedule field returns same schedulable field, // it means the field is already added to the view schedule. if (vs.Definition.GetField(id).GetSchedulableField() == sf) { fieldAlreadyAdded = true; break; } } //If schedulable field doesn't exist in view schedule, add it. if (fieldAlreadyAdded == false) { vs.Definition.AddField(sf); } } } } |
The ScheduleField class represents a single field in a ScheduleDefinition's list of fields. Each (non-hidden) field becomes a column in the schedule.
Most commonly, a field represents an instance or type parameter of elements appearing in the schedule. Some fields represent parameters of other related elements, like the room to which a scheduled element belongs. Fields can also represent data calculated from other fields in the schedule, specifically Formula and Percentage fields.
The ScheduleField class has properties to control column headings, both the text as well as the orientation. Column width and horizontal alignment of text within a column can also be defined.
The ScheduleField.IsHidden property can be used to hide a field. A hidden field is not displayed in the schedule, but it can be used for filtering, sorting, grouping, and conditional formatting and can be referenced by Formula and Percentage fields.
Some ScheduleFields can be totaled and if the HasTotals property is set to true, totals will be displayed if a footer row is enabled where the totals will be displayed. It can either be a grand total row at the end of the schedule or a footer row for one of the schedule's grouped fields. In a non-itemized schedule, totals are also displayed in regular rows when multiple elements appear on the same row.
ScheduleField.GetStyle() and ScheduleField.SetStyle() use the TableCellStyle class to work with the style of fields in a schedule. Using SetStyle(), various attributes of the field can be set, including the line style for the border of the cell as well as the text font, color and size.
ScheduleField.SetFormatOptions() and ScheduleField.GetFormatOptions() use the FormatOptions class to work with the formatting of a field's data. The FormatOptions class contains settings that control how to format numbers with units as strings. It contains those settings that are typically chosen by an end user in the Format dialog and stored in the document.
In the following example, all length fields in a ViewSchedule are formatted to display in feet and fractional inches.
Code Region: Formatting a field |
// format length units to display in feet and inches format public void FormatLengthFields(ViewSchedule schedule) { int nFields = schedule.Definition.GetFieldCount(); for (int n = 0; n < nFields; n++) { ScheduleField field = schedule.Definition.GetField(n); if (field.UnitType == UnitType.UT_Length) { FormatOptions formatOpts = new FormatOptions(); formatOpts.UseDefault = false; formatOpts.DisplayUnits = DisplayUnitType.DUT_FEET_FRACTIONAL_INCHES; field.SetFormatOptions(formatOpts); } } } |
The example below applies both formatting and style overrides to a given field.
Code Region: Apply formatting and style overrides to field |
public static void ApplyFormattingToField(ViewSchedule schedule, int fieldIndex) { // Get the field. ScheduleDefinition definition = schedule.Definition; ScheduleField field = definition.GetField(fieldIndex); // Build unit formatting for the field. FormatOptions options = field.GetFormatOptions(); options.UseDefault = false; options.DisplayUnits = DisplayUnitType.DUT_SQUARE_INCHES; options.UnitSymbol = UnitSymbolType.UST_IN_SUP_2; // Build style overrides for the field // Use override options to indicate fields that are overridden and apply changes TableCellStyle style = field.GetStyle(); TableCellStyleOverrideOptions overrideOptions = style.GetCellStyleOverrideOptions(); overrideOptions.BackgroundColor = true; style.BackgroundColor = new Color(0x00, 0x00, 0xFF); overrideOptions.FontColor = true; style.TextColor = new Color(0xFF, 0xFF, 0xFF); overrideOptions.Italics = true; style.IsFontItalic = true; style.SetCellStyleOverrideOptions(overrideOptions); double width = field.GridColumnWidth; using (Transaction t = new Transaction(schedule.Document, "Set style etc")) { t.Start(); field.SetStyle(style); field.SetFormatOptions(options); // Change column width (affects width in grid and on sheet) - units are in Revit length units - ft. field.GridColumnWidth = width + 0.5; t.Commit(); } } |
Display of the schedule title and/or headers is optional. Whether the title or headers are shown can be controlled with the ScheduleDefinition properties ShowTitle and ShowHeaders.
A schedule may be sorted or grouped by one or more of the schedule's fields. Several methods can be used to control grouping and sorting of fields. The ScheduleSortGroupField class represents one of the fields that the schedule is sorted or grouped by. Sorting and grouping are related operations. In either case, elements appearing in the schedule are sorted based on their values for the field by which the schedule is sorted/grouped, which automatically causes elements with identical values to be grouped together. By enabling extra header, footer, or blank rows, visual separation between groups can be achieved.
If the ScheduleDefinition.IsItemized property is false, elements having the same values for all of the fields used for sorting/grouping will be combined onto the same row. Otherwise the schedule displays each element on a separate row
A schedule can be sorted or grouped by data that is not displayed in the schedule by marking the field used for sorting/grouping as hidden using the ScheduleField.IsHidden property.
Code Region: Add grouping/sorting to schedule |
public static void AddGroupingToSchedule(ViewSchedule schedule, BuiltInParameter paramEnum, bool withTotalsAndDecoration, ScheduleSortOrder order) { // Find field ScheduleField field = FindField(schedule, paramEnum); if (field == null) throw new Exception("Unable to find field."); // Build sort/group field. ScheduleSortGroupField sortGroupField = new ScheduleSortGroupField(field.FieldId, order); if (withTotalsAndDecoration) { sortGroupField.ShowFooter = true; sortGroupField.ShowFooterTitle = true; sortGroupField.ShowFooterCount = true; sortGroupField.ShowHeader = true; sortGroupField.ShowBlankLine = true; } // Add the sort/group field ScheduleDefinition definition = schedule.Definition; using (Transaction t = new Transaction(schedule.Document, "Add sort/group field")) { t.Start(); definition.AddSortGroupField(sortGroupField); t.Commit(); } } public static ScheduleField FindField(ViewSchedule schedule, BuiltInParameter paramEnum) { ScheduleDefinition definition = schedule.Definition; ScheduleField foundField = null; ElementId paramId = new ElementId(paramEnum); foreach (ScheduleFieldId fieldId in definition.GetFieldOrder()) { foundField = definition.GetField(fieldId); if (foundField.ParameterId == paramId) { return foundField; } } return null; } |
Headers can also be grouped. ViewSchedule.GroupHeaders() method can be used to specify which rows and columns to include in a grouping of the header section. The last parameter is a string for the caption of the grouped rows and columns.
In the following example, columns are grouped for a newly created single-category schedule.
Code Region: Grouping headers |
public static void CreateSingleCategoryScheduleWithGroupedColumnHeaders(Document doc) { using (Transaction t = new Transaction(doc, "Create single-category with grouped column headers")) { // Build the schedule t.Start(); ViewSchedule vs = ViewSchedule.CreateSchedule(doc, new ElementId(BuiltInCategory.OST_Windows)); AddRegularFieldToSchedule(vs, new ElementId(BuiltInParameter.WINDOW_HEIGHT)); AddRegularFieldToSchedule(vs, new ElementId(BuiltInParameter.WINDOW_WIDTH)); AddRegularFieldToSchedule(vs, new ElementId(BuiltInParameter.ALL_MODEL_MARK)); AddRegularFieldToSchedule(vs, new ElementId(BuiltInParameter.ALL_MODEL_COST)); doc.Regenerate(); // Group the headers in the body section using ViewSchedule methods vs.GroupHeaders(0, 0, 0, 1, "Size"); vs.GroupHeaders(0, 2, 0, 3, "Other"); vs.GroupHeaders(0, 0, 0, 3, "All"); t.Commit(); } } public static void AddRegularFieldToSchedule(ViewSchedule schedule, ElementId paramId) { ScheduleDefinition definition = schedule.Definition; // Find a matching SchedulableField SchedulableField schedulableField = definition.GetSchedulableFields().FirstOrDefault<SchedulableField>(sf => sf.ParameterId == paramId); if (schedulableField != null) { // Add the found field definition.AddField(schedulableField); } } |
A ScheduleFilter can be used to filter the elements that will be displayed in a schedule. A filter is a condition that must be satisfied for an element to appear in the schedule. All filters must be satisfied for an element to appear in the schedule.
A schedule can be filtered by data that is not displayed in the schedule by marking the field used for filtering as hidden using the ScheduleField.IsHidden property.
Code Region: Add filter to schedule |
public static void AddFilterToSchedule(ViewSchedule schedule, ElementId levelId) { // Find level field ScheduleDefinition definition = schedule.Definition; ScheduleField levelField = FindField(schedule, BuiltInParameter.ROOM_LEVEL_ID); // Add filter using (Transaction t = new Transaction(schedule.Document, "Add filter")) { t.Start(); // If field not present, add it if (levelField == null) { levelField = definition.AddField(ScheduleFieldType.Instance, new ElementId(BuiltInParameter.ROOM_LEVEL_ID)); } // Set field to hidden levelField.IsHidden = true; ScheduleFilter filter = new ScheduleFilter(levelField.FieldId, ScheduleFilterType.Equal, levelId); definition.AddFilter(filter); t.Commit(); } } /// <summary> /// Finds an existing ScheduleField matching the given parameter /// </summary> /// <param name="schedule"></param> /// <param name="paramEnum"></param> /// <returns></returns> public static ScheduleField FindField(ViewSchedule schedule, BuiltInParameter paramEnum) { ScheduleDefinition definition = schedule.Definition; ScheduleField foundField = null; ElementId paramId = new ElementId(paramEnum); foreach (ScheduleFieldId fieldId in definition.GetFieldOrder()) { foundField = definition.GetField(fieldId); if (foundField.ParameterId == paramId) { return foundField; } } return null; } |
The following example shows how to determine the list of elements in a schedule.
Code Region: Get a schedule's contents |
public static void GetScheduleContents(ViewSchedule viewSchedule) { // Collect types displayed in the schedule FilteredElementCollector typeCollector = new FilteredElementCollector(viewSchedule.Document, viewSchedule.Id); typeCollector.WhereElementIsElementType(); int numberOfTypes = typeCollector.Count(); // Collect instances displayed in the schedule FilteredElementCollector instCollector = new FilteredElementCollector(viewSchedule.Document, viewSchedule.Id); instCollector.WhereElementIsNotElementType(); int numberOfInstances = instCollector.Count(); TaskDialog.Show("Elements in schedule", String.Format("Types {0} instances {1}", numberOfTypes, numberOfInstances)); } |
To work with the actual data in the schedule, the ViewSchedule.GetTableData() returns a TableData object that holds most of the data that describe the style and contents of the rows, columns, and cells in a table. More information can be found under TableView and TableData.