Retrieving Schedules on a Sheet

Guy Robinson recently explained an easy way to access all elements in a schedule.

Victor Chekalin picked up and expanded on that.

Here is his solution to retrieve all schedules in a view and elements from a schedule. In his own words:

One wonderful day I had to retrieve schedules which are presented on a sheet:

Schedules on a sheet

At first I looked at the Revit API Help but unfortunately there is no method such as GetSchdulesOnView in the ViewSheet class. There is no explicit way to get it. After a couple of hours trying to achieve that I need I encountered Guy's simple solution to access all elements in a schedule. The solution is use FilteredElementCollector and pass in the element id of the view in which you want to collect elements.

I created the following simple extension method GetSchedules to get schedules on view:

  public static class ViewSheetExtensions
  {
    public static IEnumerable<ViewSchedule>
      GetSchedules( this ViewSheet viewSheet )   
    {
      var doc = viewSheet.Document;
 
      FilteredElementCollector collector =
        new FilteredElementCollector(
          doc, viewSheet.Id );
 
      var scheduleSheetInstances =
        collector
          .OfClass( typeof( ScheduleSheetInstance ) )
          .ToElements()
          .OfType<ScheduleSheetInstance>();
 
      foreach( var scheduleSheetInstance in
        scheduleSheetInstances )
      {
        var scheduleId =
          scheduleSheetInstance
            .ScheduleId;
 
        if( scheduleId == ElementId.InvalidElementId )
          continue;
 
        var viewSchedule =
          doc.GetElement( scheduleId )
          as ViewSchedule;
 
        if( viewSchedule != null )
          yield return viewSchedule;
      }
    }
  }

It can be used like this:

  var schedules = viewSheet
    .GetSchedules()
    .ToList();

  foreach( var viewSchedule in schedules )
  {
    // Do something
  }

Here is the demo result:

Demo result

But I decided not to stop and go deeper. The next step is to get all elements which are involved in a schedule. The approach is the same as with schedules. Using FiltereredElementCollector but instead of the ViewSheet element id we pass in the ViewSchedule id.

The extension method is similar:

  public static class ViewScheduleExtensions
  {
    public static IEnumerable<ElementId>
      GetElementIdsInSchedule(
        this ViewSchedule viewSchedule )
    {
      var doc = viewSchedule.Document;
 
      FilteredElementCollector collector =
        new FilteredElementCollector(
          doc, viewSchedule.Id );
 
      var elementIds = collector
        .WhereElementIsNotElementType()
        .ToElementIds();
 
      return elementIds;
    }
  }

But there is an additional little nuance. If I retrieve elements from a material takeoff schedule, the method will return all materials in the project together with other elements. The solution is to just skip all elements which are materials:

  foreach( var id in elementIds )
  {
    var element = doc.GetElement( id );
 
    if( element is Material )
      continue;
 
    // Do something
  }

Here is the result of my demo project:

Demo result

I attached the demo Visual Studio solution and Revit project.

I hope this information will useful for developers.

Have a nice day,
Victor.