Monday, March 23, 2009

Revit: How to print sheets in order.

I’ve had a bit of fun lately working with the Revit 2009/2010 API for printing views. There is a useful SDK sample, ‘ViewPrinter’ which shows you how to replicate the print menu in revit, but using the API.

I’ve created a customized version of this that links in with our companies document management systems, and does things like prints, renames, and copies PDFs to the correct directory all with the press of a button.

This has been working well for our drafters, and has sped things up, however there have been a few issues that I’ve run into whilst following the methods set out in ViewPrinter and in the SDK documentation. Most of them relate to selecting certain views (in this case, sheets) and printing them in the correct order, and with the correct amount of copies.

The way the SDK sample does this, is it gathers a list of the sheet names the user selected, compares their names with those in the PrintMan.ViewSheetSetting.AvailableViews list and selects ones that match. It then adds these into a ViewSet, and supplies that to PrintMan and calls SubmitPrint().

   1: //create Viewset store those you need to print
   2: ViewSet viewsToPrint = new ViewSet();
   3:  
   4: //Compare your list of sheets, to those in AvailableViews
   5: foreach (string name in selectedSheetNames) 
   6: {
   7:     foreach (View view in _printMan.ViewSheetSetting.AvailableViews)
   8:      {
   9:         if (view.ViewType == ViewType.DrawingSheet)
  10:         {
  11:             //cast to viewsheet
  12:             ViewSheet vs = view as ViewSheet;
  13:  
  14:             if (vs != null && name.Contains(vs.SheetNumber + " - " + vs.Name))
  15:             {
  16:                 viewsToPrint.Insert(vs);
  17:             }
  18:         }
  19:      }
  20: }
  21:  
  22: ViewSheetSet viewSheetSet = m_viewSheetSetting.CurrentViewSheetSet;
  23: viewSheetSet.Views = selectedViews;
  24: m_viewSheetSetting.Save();
  25:  
  26: //set copies
  27: _printMan.CopyNumber = numCopies;
  28:  
  29: //submit print
  30: _printMan.SubmitPrint(v); 
  31:  
  32:  

This works great ok normally, however there is a significant problem. The problem lies in how the views are stored. The views are placed into a ViewSet, which is an implementation of the Set collection type, ie, an unordered set of items. Unfortunately, this means that us coders have no say in how the prints get ordered.

My experimentation shows that revit seems to order them by ElementID, or, in the order they were created. So lets say you create Sheet 1, Sheet 2, Sheet 4, Sheet 3, in that order. That is exactly how they will come out of the printer, even though the user would assume otherwise.

My workaround for this, after much trial and error, is this:

   1: //create a list of view tp store those you need to print
   2: List<View> viewsToPrint = new List<View>();
   3:  
   4: //Compare your list of sheets, to those in AvailableViews
   5: foreach (string name in selectedSheetNames) 
   6: {
   7:     foreach (View view in _printMan.ViewSheetSetting.AvailableViews)
   8:      {
   9:         if (view.ViewType == ViewType.DrawingSheet)
  10:         {
  11:             //cast to viewsheet
  12:             ViewSheet vs = view as ViewSheet;
  13:  
  14:             if (vs != null && name.Contains(vs.SheetNumber + " - " + vs.Name))
  15:             {
  16:                 viewsToPrint.Add(vs);
  17:             }
  18:         }
  19:      }
  20: }
  21: //loop through copies 
  22: for (int i = 1; i <= numCopies; i++) 
  23: { 
  24:  //loop through each view 
  25:  foreach (View v in viewsToPrint) 
  26:  { 
  27:   //submit print of just 1 view 
  28:    _printMan.SubmitPrint(v); 
  29:   } 
  30: }

There are a number of steps behind the scenes (such as setting up _printMan aka my PrintManager to have the correct settings) but instead of supplying PrintManager with a ViewSet of views I want to print, and changing the CopyNumber to how many times I wish to print them, I’m printing one view at a time using the overload for SubmitPrint. This allows me to order my list of selectedSheetNames in the way I wish it to come out, including sorting and reversing it. I’ve also done a for loop to replicate the CopyNumber property.

Now, at long last, my prints are coming out in the correct order!

Note: This code was created for Revit 2010, not fully tested in 2009, though most of it should work the same.

1 comment:

NAyche said...

Rod,
thank you for this hint; however, I am not sure it will lead to a practical solution. I think Autodesk should implement IComparable in the View class to allow for List(View).Sort()
Sorry: I had to use '()' instead of '<' and '>' signs because of html tags not allowed.

Question:

I am having a hard time with the end part of printing. I appreciate it if you can provide a feedback on any issue. My biggest problem was populating the ViewSet (Sheets) back to the print manager so I had to SaveAs() a set and then assign it back to CurrentViewSheetSet. Here is the code:
[
ViewSheetSetting viewSheetSetting = ptManager.ViewSheetSetting;
ViewSheetSet viewsToPrint = viewSheetSetting.CurrentViewSheetSet;
ViewSet tmpViewSet = new ViewSet();
foreach (View tmpView in ptManager.ViewSheetSetting.AvailableViews)
{
if (tmpView != null && tmpView is ViewSheet)
{ tmpViewSet.Insert(tmpView); }
}

viewsToPrint.Views = tmpViewSet;
if (viewSheetSetting.CurrentViewSheetSet != viewsToPrint)
{ viewSheetSetting.CurrentViewSheetSet = viewsToPrint;
}
try
{
viewSheetSetting.Save();
catch { }