//Here, the families or types will be made private static void CreateFamilyTypesFromTable(UIApplication uiApp, MainUI uiForm, string saveDirectory, DataGridView dgv, SaveAsOptions saveAsOptions, string familyFileToUse) { //First thing to do is open the family document and access the FamilyManager RVTDocument famDoc = RVTOperations.OpenRevitFile(uiApp, familyFileToUse); FamilyManager famMan = famDoc.FamilyManager; string tempFamilyPath = ""; //Next, delete all of the family types except one from the family and save the file off for temporary use try { //This is in a Try/Catch becuse there is a possibility for failure RVTOperations.DeleteFamilyTypes(famDoc, famMan); tempFamilyPath = saveDirectory + "\\" + String.Format(famDoc.Title).Replace(".rfa", "") + "_temp.rfa"; famDoc.SaveAs(tempFamilyPath, saveAsOptions); } catch { MessageBox.Show("Could not save out a temporary family file to the location where the families are to be saved. Verify the location is not read-only."); } //Ensure the open family gets closed finally { famDoc.Close(); } //Then, reopen the temporary family if it exists if (tempFamilyPath != "") { //Get all of the parameters in the family and add them to a dictionary indexed by the parameter name RVTDocument newFamDoc = RVTOperations.OpenRevitFile(uiApp, tempFamilyPath); FamilyManager newFamMan = newFamDoc.FamilyManager; FamilyParameterSet parameters = newFamMan.Parameters; Dictionary <string, FamilyParameter> famParamDict = new Dictionary <string, FamilyParameter>(); foreach (FamilyParameter param in parameters) { famParamDict.Add(param.Definition.Name, param); } //These integer values will be used to increment loops int rowsCount = dgv.Rows.Count; int columnsCount = dgv.Columns.Count; //Keep track of what family types were made so the script can later delete out the one that pre-existed in the family but is not needed. List <string> familyTypesMade = new List <string>(); //If the user decide to make types per row instead of families per row... if (uiForm.multiCatCFFEFamilyCreationComboBox.SelectedItem.ToString() == "Combine Types (1 File)") { //The progress bar should be prepared using the number of rows multipled by the number of columns for the number of steps to perform. This gives a better indication of progress than doing it based on the number of rows uiForm.multiCatCFFEFamiliesProgressBar.Minimum = 0; uiForm.multiCatCFFEFamiliesProgressBar.Maximum = (rowsCount - 1) * (columnsCount - 1); uiForm.multiCatCFFEFamiliesProgressBar.Step = 1; uiForm.multiCatCFFEFamiliesProgressBar.Visible = true; //Open the transaction Transaction t2 = new Transaction(newFamDoc, "MakeNewTypes"); t2.Start(); //The maximum of rows is greater than the maximum index value by 1, so this uses < to stop before an index out of range exception occurs. Also, the index starts at 1 instead of 0 because the top row is the info about the data type for (int i = 1; i < rowsCount; i++) { //The type name is in the first column. string newTypeName = dgv.Rows[i].Cells[0].Value.ToString(); //This operation will get the existing type names in the family as new ones are added to avoide duplication Dictionary <string, FamilyType> existingTypeNames = RVTOperations.GetFamilyTypeNames(newFamMan); //If the type does not exist in the dictionary... if (!existingTypeNames.Keys.Contains(newTypeName)) { //Create a new type and add it to the list of types made FamilyType newType = newFamMan.NewType(newTypeName); newFamMan.CurrentType = newType; familyTypesMade.Add(newType.Name); } else { //Otherwise set the current type in the family manager to the pre-existing one with the name of the one to be created newFamMan.CurrentType = existingTypeNames[newTypeName]; //Add that one to the list of types made, though it wasn't actually made familyTypesMade.Add(newFamMan.CurrentType.Name); } //Next, cycle through the columns, again starting with the column at index 1 and incrementing the columns to one less than the number of columns for (int j = 1; j < columnsCount; j++) { //Get the parameter name from the first column's header text string paramName = dgv.Columns[j].HeaderText; //Get the storage type from the first row string paramStorageTypeString = dgv.Rows[0].Cells[j].Value.ToString(); var paramValue = dgv.Rows[i].Cells[j].Value; //Assuming the parameter value is set... if (paramValue.ToString() != "") { //Set the parameter given the information about the FamilyManager, parameter definition, parameter type, parameter data type, value to set, and whether or not to convert inches to feet. Because this script relies on inch input, this needs done to convert to feet used by the Revit API FamilyParameter param = famParamDict[paramName]; ParameterType paramType = param.Definition.ParameterType; RVTOperations.SetFamilyParameterValue(newFamMan, param, paramType, paramStorageTypeString, paramValue, true); } //Step forward the progress bar for this parameter uiForm.multiCatCFFEFamiliesProgressBar.PerformStep(); } } t2.Commit(); //In another transaction, delete the pre-existing type used to generate the other types Transaction t3 = new Transaction(newFamDoc, "DeleteOldTypes"); t3.Start(); foreach (FamilyType type in newFamMan.Types) { //Set the current type to the one with the pre-existing type name and delete it if (!familyTypesMade.Contains(type.Name)) { newFamMan.CurrentType = type; newFamMan.DeleteCurrentType(); } } t3.Commit(); //Save out the family to the directory and remove the _temp from the name newFamDoc.SaveAs(saveDirectory + "\\" + String.Format(newFamDoc.Title).Replace("_temp", "") + ".rfa", saveAsOptions); newFamDoc.Close(); } //If the user chose to make a family file per row, the family will be saved out multiple times else if (uiForm.multiCatCFFEFamilyCreationComboBox.SelectedItem.ToString() == "1 Family Per Type (Multiple Files)") { //Set the number of steps for the progress bar to the number of rows with families to make uiForm.multiCatCFFEFamiliesProgressBar.Minimum = 0; uiForm.multiCatCFFEFamiliesProgressBar.Maximum = rowsCount - 1; uiForm.multiCatCFFEFamiliesProgressBar.Step = 1; uiForm.multiCatCFFEFamiliesProgressBar.Visible = true; //Again, starting at row index 1 because the first is the information about the data types. This loop will produce a family per row. One familly will be opened and saved off multiple times, performing the process of deleting types, adding a default type, and setting parameters before each save for (int i = 1; i < rowsCount; i++) { Transaction t2 = new Transaction(newFamDoc, "MakeNewTypes"); t2.Start(); //Create a new type using the name of the type in the first column FamilyType newType = newFamMan.NewType(dgv.Rows[i].Cells[0].Value.ToString()); //Clean up the family file name by leaving everything that does not pass the regular expression in CleanFileName string saveName = GeneralOperations.CleanFileName(newType.Name); if (saveName != "") { //Assuming nothing went wrong modifying the family name... newFamMan.CurrentType = newType; //Cycle through the columns to set the parameter values this performs the same operations as those above for making 1 family with multiple types for (int j = 1; j < columnsCount; j++) { string paramName = dgv.Columns[j].HeaderText; string paramStorageTypeString = dgv.Rows[0].Cells[j].Value.ToString(); var paramValue = dgv.Rows[i].Cells[j].Value; if (paramValue.ToString() != "") { FamilyParameter param = famParamDict[paramName]; ParameterType paramType = param.Definition.ParameterType; RVTOperations.SetFamilyParameterValue(newFamMan, param, paramType, paramStorageTypeString, paramValue, true); } } t2.Commit(); //Again, do another transaction to delete the pre-existing type Transaction t3 = new Transaction(newFamDoc, "DeleteOldTypes"); t3.Start(); foreach (FamilyType type in newFamMan.Types) { newFamMan.CurrentType = type; if (newFamMan.CurrentType.Name != newType.Name) { newFamMan.DeleteCurrentType(); } } t3.Commit(); //Save out the family and continue the loop newFamDoc.SaveAs(saveDirectory + "\\" + saveName + ".rfa", saveAsOptions); uiForm.multiCatCFFEFamiliesProgressBar.PerformStep(); } } // The family document is finally closed after saving off itself for each row newFamDoc.Close(); } else { MessageBox.Show("No Creation Method was selected"); } //Delete the _temp file File.Delete(tempFamilyPath); //Clean up the backup files too List <string> backupFiles = GeneralOperations.GetAllRvtBackupFamilies(uiForm.multiCatCFFEFamilySaveLocation, false); GeneralOperations.CleanRfaBackups(backupFiles); } }
public MaterialsCMSRequest(UIApplication uiApp, String text) { MainUI uiForm = BARevitTools.Application.thisApp.newMainUi; ProgressBar progressBar = uiForm.materialsCMSExcelCreateSymbolsProgressBar; DataGridView dgv = uiForm.materialsCMSExcelDataGridView; int rowsCount = dgv.Rows.Count; int columnsCount = dgv.Columns.Count; List <string> familyTypesMade = new List <string>(); //Prepare the progress bar. The column count is one less because the first column is the column for family type names progressBar.Minimum = 0; progressBar.Maximum = (rowsCount) * (columnsCount - 1); progressBar.Step = 1; progressBar.Visible = true; RVTDocument doc = uiApp.ActiveUIDocument.Document; //Reset the progress bar uiForm.materialsCMSExcelCreateSymbolsProgressBar.Value = 0; //First, try to use the family from the project. If that fails, use the family file Family familyToUse = RVTGetElementsByCollection.FamilyByFamilyName(uiApp, Path.GetFileNameWithoutExtension(Properties.Settings.Default.RevitFamilyMaterialsCMSSymbIdMaterialSchedule)); //Assuming nothing went to hell in the process of loading one famiy... if (familyToUse != null) { //Save out the family to use RVTDocument tempFamDoc = doc.EditFamily(familyToUse); RVTOperations.SaveRevitFile(uiApp, tempFamDoc, @"C:\Temp\" + tempFamDoc.Title, true); //Open the family to use and get its FamilyManager RVTDocument famDoc = RVTOperations.OpenRevitFile(uiApp, @"C:\Temp\" + Path.GetFileName(Properties.Settings.Default.RevitFamilyMaterialsCMSSymbIdMaterialSchedule)); FamilyManager famMan = famDoc.FamilyManager; //Get the parameters from the Family Manager and add them to a dictionary FamilyParameterSet parameters = famMan.Parameters; Dictionary <string, FamilyParameter> famParamDict = new Dictionary <string, FamilyParameter>(); foreach (FamilyParameter param in parameters) { famParamDict.Add(param.Definition.Name, param); } //Start a new transaction to make the new family types in the family to use using (Transaction t1 = new Transaction(famDoc, "MakeNewTypes")) { t1.Start(); //Cycle through the rows in the dgv for (int i = 0; i < rowsCount; i++) { //The first column cell will be the type name string newTypeName = dgv.Rows[i].Cells[0].Value.ToString(); //Get the family type names in the family Dictionary <string, FamilyType> existingTypeNames = RVTOperations.GetFamilyTypeNames(famMan); //If the family to make from the DGV does not exist in the dictionary keys... if (!existingTypeNames.Keys.Contains(newTypeName)) { //Make the family type and add it to the list of types made FamilyType newType = famMan.NewType(newTypeName); famMan.CurrentType = newType; familyTypesMade.Add(newType.Name); } else { //If the type exists, set the current type it from the dictionary and add it to the list of types made famMan.CurrentType = existingTypeNames[newTypeName]; familyTypesMade.Add(famMan.CurrentType.Name); } //Next, evaluate the columns that contain parameters for (int j = 1; j < columnsCount; j++) { //The parameter names will be retrieved from the column HeaderText property string paramName = dgv.Columns[j].HeaderText; //Meanwhile the parameter value will come from the DGV cells var paramValue = dgv.Rows[i].Cells[j].Value; try { //If the parameter dictionary contains the parameter and the value to assign it is not empty, continue. if (paramValue.ToString() != "" && famParamDict.Keys.Contains(paramName)) { //Get the family parameter and check if it is locked by a formula FamilyParameter param = famParamDict[paramName]; if (!param.IsDeterminedByFormula) { //If it is not locked by a formula, set the parameter ParameterType paramType = param.Definition.ParameterType; RVTOperations.SetFamilyParameterValue(famMan, param, paramValue); } } } catch {; } finally { //Always perform the step to indicate the progress. progressBar.PerformStep(); } } } t1.Commit(); } //Use another transaction to delete the types that were not needed using (Transaction t2 = new Transaction(famDoc, "DeleteOldTypes")) { t2.Start(); //Cycle through the family types and determine if it is in the list of types made foreach (FamilyType type in famMan.Types) { if (!familyTypesMade.Contains(type.Name)) { //If the type is not in the list of types made, delete it from the family file famMan.CurrentType = type; famMan.DeleteCurrentType(); } } t2.Commit(); } //Save the family document at this point as all of the types and their parameters have been set famDoc.Close(true); using (Transaction t3 = new Transaction(doc, "LoadFamily")) { t3.Start(); doc.LoadFamily(@"C:\Temp\" + Path.GetFileName(Properties.Settings.Default.RevitFamilyMaterialsCMSSymbIdMaterialSchedule), new RVTFamilyLoadOptions(), out Family loadedFamily); t3.Commit(); } //Get the drafting view type in the project for BA Drafting View, else just get the first drafting view type ViewDrafting placementView = null; var draftingViews = new FilteredElementCollector(doc).OfClass(typeof(ViewDrafting)).WhereElementIsNotElementType().ToElements(); ViewFamilyType draftingViewType = null; try { //From the view family types collection, get the first one where its name is BA Drafting View draftingViewType = new FilteredElementCollector(doc).OfClass(typeof(ViewFamilyType)).WhereElementIsElementType().ToElements().Where(elem => elem.Name == "BA Drafting View").First() as ViewFamilyType; } catch { //Well, crap. It doesn't exist. Just get the first type then and call it good. draftingViewType = new FilteredElementCollector(doc).OfClass(typeof(ViewFamilyType)).WhereElementIsElementType().ToElements().First() as ViewFamilyType; } //Start a transaction for making the ID Material View and placing the family symbol types using (Transaction t4 = new Transaction(doc, "MakeIDMaterialView")) { t4.Start(); foreach (ViewDrafting view in draftingViews) { //Find the view named ID Material View, or whatever jibberish someone typed in the CMS text box for the name to use. in the drafting views if (view.Name == "ID Material View" || view.Name == uiForm.materialsCMSSetViewNameTextBox.Text) { //Delete the drafting view doc.Delete(view.Id); doc.Regenerate(); break; } else { continue; } } //Make a new view placementView = ViewDrafting.Create(doc, draftingViewType.Id); placementView.Scale = 1; if (uiForm.materialsCMSSetViewNameTextBox.Text != "") { //If someone defined a custom view name, use that and strip out brackets if they exist placementView.Name = uiForm.materialsCMSSetViewNameTextBox.Text.Replace("{", "").Replace("}", ""); } else { //Otherwise, this will be the new ID Material View placementView.Name = "ID Material View"; } try { //Set the view sort parameters if they exist placementView.GetParameters(Properties.Settings.Default.BAViewSort1).First().Set("2 Plans"); placementView.GetParameters(Properties.Settings.Default.BAViewSort2).First().Set("230 Finish Plans"); } catch (Exception e) { MessageBox.Show(e.ToString()); } doc.Regenerate(); t4.Commit(); } //Do magic to place each symbol in its view by calling the method below in this class PlaceSymbolsInView(uiApp, "ID Use", "Mark", placementView); //Clean up the files from the operations GeneralOperations.CleanRfaBackups(GeneralOperations.GetAllRvtBackupFamilies(@"C:\Temp\", false)); File.Delete(@"C:\Temp\" + Path.GetFileName(Properties.Settings.Default.RevitFamilyMaterialsCMSSymbIdMaterialSchedule)); Application.thisApp.newMainUi.materialsCMSFamilyToUse = RVTGetElementsByCollection.FamilyByFamilyName(uiApp, Path.GetFileNameWithoutExtension(Properties.Settings.Default.RevitFamilyMaterialsCMSSymbIdMaterialSchedule)); } else { //If the family could not be found, well, let the user know of this. MessageBox.Show(String.Format("The {0} family could not be found in the project.", Path.GetFileNameWithoutExtension(Properties.Settings.Default.RevitFamilyMaterialsCMSSymbIdMaterialSchedule))); } }