using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using OfficeOpenXml;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Windows.Forms;
// Alias to avoid ambiguity with View
using RevitView = Autodesk.Revit.DB.View;
public enum SectionType
{
Header,
Body
}
internal class ScheduleExporter
{
private readonly ViewSchedule viewSchedule;
public ScheduleExporter(ViewSchedule input)
{
viewSchedule = input;
}
///
/// Exports the schedule data to a worksheet in the provided Excel package.
///
public void ExportToExcel(ExcelPackage excelPackage)
{
var scheduleData = new
{
viewSchedule.Name,
Header = GetSectionData(SectionType.Header),
Body = GetSectionData(SectionType.Body)
};
// Create a worksheet for the schedule
ExcelWorksheet worksheet = excelPackage.Workbook.Worksheets.Add(viewSchedule.Name);
int row = 1;
// Add the header
if (scheduleData.Header != null)
{
for (int col = 0; col < scheduleData.Header.Count; col++)
{
worksheet.Cells[row, col + 1].Value = string.Join(", ", scheduleData.Header[col]);
}
row++;
}
// Add the body
if (scheduleData.Body != null)
{
foreach (var bodyRow in scheduleData.Body)
{
for (int col = 0; col < bodyRow.Count; col++)
{
worksheet.Cells[row, col + 1].Value = bodyRow[col];
}
row++;
}
}
}
///
/// Retrieves data for a specific section of the schedule.
///
private List> GetSectionData(SectionType sectionType)
{
var data = new List>();
TableSectionData sectionData = viewSchedule.GetTableData().GetSectionData((int)sectionType);
int numberOfRows = sectionData.NumberOfRows;
int numberOfColumns = sectionData.NumberOfColumns;
for (int iRow = sectionData.FirstRowNumber; iRow < numberOfRows; iRow++)
{
var rowData = new List();
for (int iCol = sectionData.FirstColumnNumber; iCol < numberOfColumns; iCol++)
{
var cellValue = viewSchedule.GetCellText((Autodesk.Revit.DB.SectionType)sectionType, iRow, iCol);
if (!string.IsNullOrEmpty(cellValue))
{
rowData.Add(cellValue);
}
}
data.Add(rowData);
}
return data;
}
}
[Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
public class ExportAllSchedulesCommand : IExternalCommand
{
public Result Execute(
ExternalCommandData commandData,
ref string message,
ElementSet elements)
{
UIApplication uiapp = commandData.Application;
UIDocument uidoc = uiapp.ActiveUIDocument;
Document doc = uidoc.Document;
// Retrieve all ViewSchedules in the document
List schedules = new FilteredElementCollector(doc)
.OfClass(typeof(ViewSchedule))
.Cast()
.ToList();
if (schedules.Count == 0)
{
message = "No schedules were found in the document.";
return Result.Cancelled;
}
// Show save file dialog to select output file path
SaveFileDialog saveFileDialog = new SaveFileDialog
{
Title = "Save Excel File",
Filter = "Excel Files (*.xlsx;*.xlsm)|*.xlsx;*.xlsm",
FileName = ReplaceInvalidCharacters(doc.Title) + "_Schedules.xlsm",
OverwritePrompt = false
};
if (saveFileDialog.ShowDialog() != DialogResult.OK)
{
message = "The operation was cancelled by the user.";
return Result.Cancelled;
}
string excelFilePath = saveFileDialog.FileName;
try
{
ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
// If the file exists, load it; otherwise, create a new file
using (ExcelPackage excelPackage = File.Exists(excelFilePath)
? new ExcelPackage(new FileInfo(excelFilePath))
: new ExcelPackage())
{
foreach (var schedule in schedules)
{
ScheduleExporter exporter = new ScheduleExporter(schedule);
exporter.ExportToExcel(excelPackage);
}
// Save the Excel file
FileInfo excelFile = new FileInfo(excelFilePath);
excelPackage.SaveAs(excelFile);
}
// Open the Excel file automatically
ProcessStartInfo processStartInfo = new ProcessStartInfo
{
FileName = excelFilePath,
UseShellExecute = true
};
Process.Start(processStartInfo);
MessageBox.Show($"All schedules have been exported to: {excelFilePath}");
return Result.Succeeded;
}
catch (Exception ex)
{
MessageBox.Show($"An error occurred: {ex.Message}");
return Result.Failed;
}
}
///
/// Replaces invalid characters in file names with underscores.
///
private static string ReplaceInvalidCharacters(string input)
{
char[] invalidChars = Path.GetInvalidFileNameChars();
foreach (char ch in invalidChars)
{
input = input.Replace(ch, '_');
}
return input;
}
}