#RTCEUR Wish 5! View Template (partially) exported

T.R. wished for the ability to “compare two view templates to identify/highlight differences. Or a way to spit them to txt/xls for compare”

We can get the data from all parameters stored as numbers, text, and element ids. We can also query the properties of the View class. In the sample code, this is done using reflection so code does not need to be written for each property individually.

Also, GetNonControlledTemplateParameterIds returns a list of parameters that are not marked as included when this view is used as a template. GetTemplateParameterIds returns a list of parameter ids that may be controlled when this view is assigned as a template.

Sample output of all parameter values:

------PARAMETERS---------
Category,-2000279
Category,-2000279
Color Scheme Location,1
Design Option,-1
Detail Level,3
Discipline,1
Display Model,0
Edited by,
Family,
Family,
Family and Type,
Family and Type,
Family Name,
Far Clipping,0
Learning Content,
Parts Visibility,1
Phase Filter,375
Scale Value    1:,100
Show Hidden Lines,1
Sun Path,0
Type,
Type Name,
View Scale,100
View Template,-1
Workset,172
------PROPERTIES---------
AnalysisDisplayStyleId,-1
AreAnalyticalModelCategoriesHidden,False
AreAnnotationCategoriesHidden,False
AreImportCategoriesHidden,False
AreModelCategoriesHidden,False
ArePointCloudsHidden,False
AssemblyInstanceId,-1
AssociatedAssemblyInstanceId,-1
CanBePrinted,False
CreatedPhaseId,-1
DemolishedPhaseId,-1
GroupId,-1
Id,9610
IsAssemblyView,False
IsTemplate,True
IsValidObject,True
LevelId,-1
Name,Architectural Section
OwnerViewId,-1
Pinned,False
RevealConstraintsMode,False
Title,Architectural Section
UniqueId,96dd64a0-c5ef-4337-8f9b-658b5c420b33-0000258a
ViewName,Architectural Section
ViewSpecific,False
ViewTemplateId,-1
---------------
Enable Sketchy Lines,False
Sketchy Line Extension,0
Sketchy Line Jitter,0
public void exportViewTemplate()
{
    Document doc = this.ActiveUIDocument.Document;
    string templateName = "Architectural Section";
    View template = new FilteredElementCollector(doc).OfClass(typeof(View)).Cast<View>()
        .FirstOrDefault(q => q.IsTemplate == true && q.Name == templateName);
    
    using (StreamWriter sw = new StreamWriter(@"C:\Users\harry_000\Desktop\rtc\View Template Export - " + templateName + ".txt"))
    {
        // quick and easy solution to get data from simple parameters
        sw.WriteLine("------PARAMETERS---------");
        foreach (Parameter p in template.Parameters.Cast<Parameter>().OrderBy(q => q.Definition.Name))
        {
            string val = "<undefined>";
            if (p.StorageType == StorageType.Double)
                val = p.AsDouble().ToString();
            else if (p.StorageType == StorageType.Integer)
                val = p.AsInteger().ToString();
            else if (p.StorageType == StorageType.ElementId)
                val = p.AsElementId().IntegerValue.ToString();
            else if (p.StorageType == StorageType.String)
                val = p.AsString();
            
            if (val != "<undefined>")
                sw.WriteLine(p.Definition.Name + "," + val);
        }
        
        // use reflection to get values from all properties of the view class
        sw.WriteLine("------PROPERTIES---------");
        foreach (System.Reflection.PropertyInfo pi in template.GetType().GetProperties().OrderBy(q => q.Name))
        {
            string propertyName = "";
            string propertyValue = "";
            getPropertyNameAndValue(template, pi, out propertyName, out propertyValue);
            
            if (propertyValue != "<undefined>")
                sw.WriteLine(propertyName + "," + propertyValue);
        }
        
        sw.WriteLine("---------------");
        
        // complex parameters require more work to export values individually
        ViewDisplaySketchyLines sketchyLines = template.GetSketchyLines();
        sw.WriteLine("Enable Sketchy Lines," + sketchyLines.EnableSketchyLines.ToString());
        sw.WriteLine("Sketchy Line Extension," + sketchyLines.Extension.ToString());
        sw.WriteLine("Sketchy Line Jitter," + sketchyLines.Jitter.ToString());
        
    }
}

private void getPropertyNameAndValue(object o, System.Reflection.PropertyInfo pi, out string propertyName, out string propertyValue)
{
    propertyName = pi.Name;
    propertyValue = "<undefined>";
    if (pi.PropertyType == typeof(ElementId) ||
        pi.PropertyType == typeof(Boolean) ||
        pi.PropertyType == typeof(String) ||
        pi.PropertyType == typeof(Enum))
    {
        try
        {
            propertyValue = pi.GetValue(o).ToString();
        }
        catch
        {}
    }
}

#RTCEUR Wish 4 granted! Change parameter value in multiple families

Doug asked ” How about a routine to change the value of a shared parameter in all families in a folder to the same specified value.”

public void setParamInFamilies()
{
    Application app = this.Application;
    foreach (string filename in Directory.GetFiles(@"C:\Users\harry_000\Desktop\rtc", "*.rfa"))
    {
        Document doc = app.OpenDocumentFile(filename);
        using (Transaction t = new Transaction(doc, "Set param value"))
        {
            t.Start();
            
            // get the parameter to set
            FamilyParameter param = doc.FamilyManager.get_Parameter("RTC Parameter");
            
            if (param == null)
                continue;
            
            // loop through all types in the family
            foreach (FamilyType ftype in doc.FamilyManager.Types)
            {
                // set the parameter value for this type
                doc.FamilyManager.Set(param, "Budapest");
            }
            t.Commit();
            doc.Save();
            doc.Close(false);
        }
    }
}

#RTCEUR Wish #2 Granted! Rename views

Jason asked “How about a find / replace tool for view names?”

Wish granted!

public void viewRename()
{
    string find = "Level";
    string replace = "LEV";
    
    Document doc = this.ActiveUIDocument.Document;
    string errors = "";
    using (Transaction t = new Transaction(doc, "Rename views"))
    {
        t.Start();
        // find all views whose name contains the "find" string
        foreach (Element view in new FilteredElementCollector(doc).OfClass(typeof(View))
                 .Where(q => q.Name.Contains(find)))
        {
            try
            {
                view.Name = view.Name.Replace(find, replace);
            }
            catch // error handling if there is already a view with what would be the new name
            {
                errors += view.Name + ", ";
            }
        }
        t.Commit();
     }
    
    // show error dialog if there are errors
    if (errors != "")
    {
        TaskDialog td = new TaskDialog("Error");
        td.MainInstruction = "Could not rename views because duplicate names would be created";
        td.MainContent = errors;
        td.Show();
    }
}

#RTCEUR Wish 1 granted!

Chris asked how the API could help copy a legend to multiple sheets. Wish granted!

public void legendOnSheets()
{
    Document doc = this.ActiveUIDocument.Document;
    
    // create list of element ids for the sheets that will get the legends
    List<ElementId> sheetIds = new List<ElementId>();
        
    // use SheetNumber to find the desired sheets
    // add each sheet to the list of sheet ids
    sheetIds.Add(new FilteredElementCollector(doc)
        .OfClass(typeof(ViewSheet))
        .Cast<ViewSheet>()
        .FirstOrDefault(q => q.SheetNumber == "A101").Id);
    sheetIds.Add(new FilteredElementCollector(doc)
        .OfClass(typeof(ViewSheet))
        .Cast<ViewSheet>()
        .FirstOrDefault(q => q.SheetNumber == "A102").Id);                
    sheetIds.Add(new FilteredElementCollector(doc)
        .OfClass(typeof(ViewSheet))
        .Cast<ViewSheet>()
        .FirstOrDefault(q => q.SheetNumber == "A103").Id);    
    
    // find the legend to put on the sheets
    // use ViewType.Legend and the view name to find the legend view
    Element legend = new FilteredElementCollector(doc)
        .OfClass(typeof(View))
        .Cast<View>()
        .FirstOrDefault(q => q.ViewType == ViewType.Legend && q.Name == "Legend 1");
    
    // create a transaction so that the document can be modified
    using (Transaction t = new Transaction(doc, "Legends on Sheets"))
    {
        // start the transaction
        t.Start();
        
        // loop through the list of sheet ids
        foreach (ElementId sheetid in sheetIds)
        {
            // create a new viewport for the legend on each sheet
            // place the legend view at the 0,0,0 location on each sheet
            // user will need to move the legend to the desired location
            Viewport.Create(doc, sheetid, legend.Id, new XYZ(0,0,0));
        }
        
        // commit the changes
        t.Commit();
    }
}