Poetical, ain't it?
One of the major Revit 2015 API additions is access to revisions.
All prior versions provided very limited access to revision data in a project. Here are some things people achieved in spite of the limitations:
Let's now take a look at an elegant example of accessing and displaying the complete revision data in a project, GetRevisionData, prompted by the following query by Dan Tartaglia of design technology@NBBJ:
Question: Selecting the View tab in Revit and then Revisions in the Sheet Composition pane displays the 'Sheet Issues/Revisions' dialogue:
I am trying to access the information displayed programmatically, in particular the information for these revisions found in the 'Show' column with the three possible choices 'None', 'Tag' and 'Cloud and Tag'.
Is that possible?
I am currently using the GetAllProjectRevisionIds method, but that does not return all the required information.
Answer: What you ask for is now possible in Revit 2015 using the new revision classes.
I am not aware of any way to access it programmatically in Revit 2014, though. Developers have been asking for it for a long time, and that access was one of the major Revit 2015 API enhancements.
Examining your Revit 2014 GetRevisionData attempt in a little more detail, I have some comments on that before getting to the Revit 2015 solution.
It includes a nice utility method GetParameterInformation to convert a parameter value to a string representation. That is used by the ParamsFromGetAllRevElements method to retrieve all project revisions via their ids and list all their parameter values.
However, as said, it does not return the information we are after.
I fixed the architecture mismatch warnings in the initial 2014 project using my recursive project parser and fixer DisableMismatchWarning.exe.
I like the parameter to value to string converter, so let's list it here for posterity to enjoy:
/// <summary> /// Extract the parameter information. /// By Dan Tartaglia. /// </summary> public string GetParameterInformation( Parameter para, Document doc ) { string defName = ""; // Use different method to get parameter // data according to the storage type switch( para.StorageType ) { // Determine the parameter type case StorageType.Double: // Convert the number into Metric defName = para.AsValueString(); break; case StorageType.ElementId: // Find out the name of the element Autodesk.Revit.DB.ElementId id = para.AsElementId(); defName = ( id.IntegerValue >= 0 ) ? doc.GetElement( id ).Name : id.IntegerValue.ToString(); break; case StorageType.Integer: if( ParameterType.YesNo == para.Definition.ParameterType ) { if( para.AsInteger() == 0 ) { defName = "False"; } else { defName = "True"; } } else { defName = para.AsInteger().ToString(); } break; case StorageType.String: defName = para.AsString(); break; default: defName = "Unexposed parameter"; break; } return defName; }
One little suggestion I have is to encapsulate the text writer instance in a using block, e.g. like this:
using( TextWriter tw = new StreamWriter( "C:/tmp/RevisionTest.txt" ) ) { tw.WriteLine( ". . ." ); tw.Close(); }
For comparison with the Revit 2015 results, let's list the limited data accessible via the Revit 2014 API here, printed out to a text file C:/tmp/RevisionTest.txt
:
C:\tmp>cat RevisionTest.txt Hidden = False Element Name: Revisions oParamRevEnum = 0 oParamRevDate = Date 1 oParamRevDescrip = Revision 1 oParamRevIssued = False oParamRevIssuedBy = oParamRevIssuedTo = oParamRevNumber = 1 oParamSeqNumber = 1 ============================== Hidden = False Element Name: Revisions oParamRevEnum = 0 oParamRevDate = Date 2 oParamRevDescrip = Revision 2 oParamRevIssued = False oParamRevIssuedBy = oParamRevIssuedTo = oParamRevNumber = 2 oParamSeqNumber = 2 ============================== Hidden = False Element Name: Revisions oParamRevEnum = 0 oParamRevDate = Date 5 oParamRevDescrip = Revision 5 oParamRevIssued = False oParamRevIssuedBy = oParamRevIssuedTo = oParamRevNumber = 5 oParamSeqNumber = 5 ==============================
I published the Revit 2014 version in the GetRevisionData GitHub repository as version 2014.0.0.0.
Response: Yes, I verified that I can get what I need with the Revit 2015 API like this:
IList<ElementId> oElemIDs = oViewSheet.GetAllRevisionIds(); if( oElemIDs.Count == 0 ) return; foreach( ElementId elemID in oElemIDs ) { Element oEl = doc.GetElement( elemID ); Revision oRev = oEl as Revision; // Add text line to text file tw.WriteLine( "Rev Category Name: " + oRev.Category.Name ); // Add text line to text file tw.WriteLine( "Rev Description: " + oRev.Description ); // Add text line to text file tw.WriteLine( "Rev Issued: " + oRev.Issued.ToString() ); // Add text line to text file tw.WriteLine( "Rev Issued By: " + oRev.IssuedBy.ToString() ); // Add text line to text file tw.WriteLine( "Rev Issued To: " + oRev.IssuedTo.ToString() ); // Add text line to text file tw.WriteLine( "Rev Number Type: " + oRev.NumberType.ToString() ); // Add text line to text file tw.WriteLine( "Rev Date: " + oRev.RevisionDate ); // Add text line to text file tw.WriteLine( "Rev Visibility: " + oRev.Visibility.ToString() ); // Add text line to text file tw.WriteLine( "Rev Sequence Number: " + oRev.SequenceNumber.ToString() ); // Add text line to text file tw.WriteLine( "Rev Number: " + oRev.RevisionNumber ); }
Answer: Congratulations on solving it!
I am glad that the Revit 2015 API provides all you need.
I implemented a sample command grabbing all the revision data displayed in the Revit 'Sheet Issues/Revisions' form and displaying that in a Windows form generated on the fly.
It avoids the text writer and file output completely by implementing a revision data holder class and a container dictionary, using a Windows forms data grid view container and its DataSource property to access and display the data:
It demonstrates several other nice features, in addition to the revision functionality:
- Accessing and displaying all the revision information without ever actually touching or formatting any individual data members.
- Generating a Windows form programmatically on the fly.
- Populating a DataGridView via its DataSource property.
The Revit 2015 version is published in the GetRevisionData GitHub repository as version 2015.0.0.0.
The hardest challenge was actually not implementing the DataGridView population, but the automatic resizing. That took quite a while, testing and debugging numerous combinations of the automatic resizing properties until finally finding one that worked.
The complete external command implementation defines just three simple little items:
- RevisionData – a container for the revision data displayed in the Revit 'Sheet Issues/Revisions' dialogue.
- DisplayRevisionData – generate a Windows modeless form on the fly and display the revision data in it in a DataGridView.
- Execute – external command mainline.
Each one on its own is pretty trivial.
Together, they form a rally neat and elegant solution, I think:
#region Namespaces using System; using System.Collections.Generic; using System.Data; using System.Diagnostics; using System.Drawing; using System.IO; using System.Windows.Forms; using Autodesk.Revit.ApplicationServices; using Autodesk.Revit.Attributes; using Autodesk.Revit.DB; using Autodesk.Revit.UI; using Autodesk.Windows; using TaskDialog = Autodesk.Revit.UI.TaskDialog; #endregion namespace GetRevisionData { /// <summary> /// External command demonstrating how to use the /// Revit 2015 Revision API to retrieve and display /// all infoormation shown in the Revit /// 'Sheet Issues/Revisions' dialogue. /// </summary> [Transaction( TransactionMode.ReadOnly )] public class Command : IExternalCommand { /// <summary> /// A container for the revision data displayed in /// the Revit 'Sheet Issues/Revisions' dialogue. /// </summary> class RevisionData { public int Sequence { get; set; } public RevisionNumberType Numbering { get; set; } public string Date { get; set; } public string Description { get; set; } public bool Issued { get; set; } public string IssuedTo { get; set; } public string IssuedBy { get; set; } public RevisionVisibility Show { get; set; } public RevisionData( Revision r ) { Sequence = r.SequenceNumber; Numbering = r.NumberType; Date = r.RevisionDate; Description = r.Description; Issued = r.Issued; IssuedTo = r.IssuedTo; IssuedBy = r.IssuedBy; Show = r.Visibility; } } /// <summary> /// Generate a Windows modeless form on the fly /// and display the revision data in it in a /// DataGridView. /// </summary> void DisplayRevisionData( List<RevisionData> revision_data, IWin32Window owner ) { System.Windows.Forms.Form form = new System.Windows.Forms.Form(); form.Size = new Size( 680, 180 ); form.Text = "Revision Data"; DataGridView dg = new DataGridView(); dg.DataSource = revision_data; dg.AllowUserToAddRows = false; dg.AllowUserToDeleteRows = false; dg.AllowUserToOrderColumns = true; dg.Dock = System.Windows.Forms.DockStyle.Fill; dg.Location = new System.Drawing.Point( 0, 0 ); dg.ReadOnly = true; dg.TabIndex = 0; dg.Parent = form; dg.AutoSize = true; dg.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells; dg.AutoResizeColumns( DataGridViewAutoSizeColumnsMode.AllCells ); dg.AutoResizeColumns(); form.ShowDialog( owner ); } public Result Execute( ExternalCommandData commandData, ref string message, ElementSet elements ) { IWin32Window revit_window = new JtWindowHandle( ComponentManager.ApplicationWindow ); UIApplication uiapp = commandData.Application; UIDocument uidoc = uiapp.ActiveUIDocument; Document doc = uidoc.Document; if( doc.IsFamilyDocument ) { TaskDialog.Show( "Not a Revit RVT Project", "This command requires an active Revit RVT file." ); return Result.Failed; } if( !( doc.ActiveView is ViewSheet ) ) { TaskDialog.Show( "Current View is not a Sheet", "This command requires an active sheet view." ); return Result.Failed; } IList<ElementId> ids = Revision.GetAllRevisionIds( doc ); int n = ids.Count; List<RevisionData> revision_data = new List<RevisionData>( n ); foreach( ElementId id in ids ) { Revision r = doc.GetElement( id ) as Revision; revision_data.Add( new RevisionData( r ) ); } DisplayRevisionData( revision_data, revit_window ); return Result.Succeeded; } } }
Enjoy!
Next time I write will be from Toronto, إن شاء الله (insha'Allah, God willing).
Hi Jeremy,
I had the issue with auto-sizing gridview columns also.
I did a little research, and found that it's easier to set it per column (hope this formats okay!):
Public Sub SetDataGridColumnWidthMode(ByVal column As Integer, ByVal mode As DataGridViewAutoSizeColumnMode)
dgData.Columns(column).AutoSizeMode = mode
End Sub
mainForm.SetDataGridColumnWidthMode(2, DataGridViewAutoSizeColumnMode.DisplayedCells)
mainForm.SetDataGridColumnWidthMode(3, DataGridViewAutoSizeColumnMode.Fill)
Posted by: Matt Taylor | June 02, 2014 at 20:25
Dear Matt,
Thank you for the suggestion!
Did you try it out in this case?
I did, and it appears that due to my usage of the DataSource property, I have no columns in that sense.
The Count property of Columns is zero, so attempting to make calls like this throws an exception:
dg.Columns[2].AutoSizeMode
= DataGridViewAutoSizeColumnMode.DisplayedCells;
dg.Columns[3].AutoSizeMode
= DataGridViewAutoSizeColumnMode.Fill;
Cheers, Jeremy.
Posted by: Jeremy Tammik | June 03, 2014 at 21:08
Hi Jeremy,
Ah, sorry that didn't help. (I didn't test it.)
The thing I used it for was printer devices, their status, and queue length etc (read-only), so a DataTable was a perfect Datasource for that.
From what I read about the column count on the datasource (list) issue, it's to do with late-binding of data - so I guess your solution works best!!
I hope you're having fun in Toronto!
Kind regards,
Matt
Posted by: Matt Taylor | June 04, 2014 at 01:37
Dear Matt,
Thank you for the suggestion, anyway, and for your good wishes!
Cheers, Jeremy.
Posted by: Jeremy Tammik | June 04, 2014 at 20:02
Hello Jeremy,
I didn't understand the above example completely.
I have questions like: which file are you talking about ? there is no namespace and the filename + extension.
I am a very layman person, just started working 2 days before on Revit 2016.
Need to ask you how to get started with creating a solution (class library / usercontrol library / wpf application) and connect with Revit, there are no proper guidelines for this.
Can you make a layman blog post for me and for the starters.
I am very desperate to learn this tech.
Posted by: Vipul Surana | May 23, 2015 at 03:18
Dear Vipul,
You will be very happy to hear that we have already created a full set of getting started material:
http://thebuildingcoder.typepad.com/blog/about-the-author.html#2
I guarantee that it covers all your needs :-)
Cheers, Jeremy.
Posted by: Jeremy Tammik | May 26, 2015 at 03:53