The ViewSchedule.GetTableData method allows you to get at the data in an existing schedule. However, the problem we are running into is how to determine what Element each row in the SectionType.Body of the TableData applies to? Is there a way when running through the TableData to determine the Element each row is refering to?
Thanks for your help,
Dave Blackburn
Solved! Go to Solution.
Solved by RevitArkitek. Go to Solution.
I've struggled with this also, and as far as I know you cannot get this directly from the schedule. But there is a workaround. You can do a FilteredElementCollector of the schedule using its ElementId for the view input. So now you know what elements can be shown in the schedule.
The problem is that schedules can be filtered, sorted, and not itemized. (If the schedule is not itemized you are effectively looking at multiple elements in a single row.) So what I ended up doing was creating an ID text parameter for the category (or all categories). Add the ID parameter to your schedule and set the IsItemized to true. As you iterate over the elements in your FEC, set the ID. (Since we can't add the ElementId param to a schedule.) Now you can get the ID for each row in the schedule to know what element it was.
Hi,
see also:
In fact, the workaround wouldn't be necessary if Autodesk would just provide a simple TabelSectionData.GetRowElementId(int rowIndex) method...
Revitalizer
Or in the case of un-itemized schedules, a list of ElementIds. I think the API engineers have been asleep the last couple of versions. We only seem to get the new Revit features or this useless Revit Server stuff.
I understand the concept here, but have run into problems on the execution. Can either of you offer some help? Here is what I have working:
The problem arises when I attempt to find the element of the row in the TableData -
Step 2 & 3 are the problems. GetCellParamId returns an ElementId. I can open that element via document.GetElement and it appears to be my parameter (at least it has the same name as my parameter), but I didn't think Parameters were Elements so I'm really confused why GetCellParamId is returning an ElementId. In any case, I can't convert that element to a Parameter in order to get at the UniqueID stored in its value. What am I missing here?
Thanks for any help you can offer!
Hi djb,
that's the point: the Parameter object is not an Element.
If you can get a valid Element by document.GetElement(parameterId) of the same name as the parameter itself, this one seems to be some sort of helper element but not your desired one.
So this is still the result:
There is no way to get the Id or UniqueId from a row.
As both RevitArkitek and I suggested, there is only an ugly workaround by adding the Element's Id.IntegerValue (or GUID) to the schedule's columns.
You can do that in a temporary transaction.
Revitalizer
Thanks for replying Revitalizer.
I had encountered your other post regarding this same thing:
Hi tssserg,
first, I set the existing value for element parameter BuiltInParameter.ALL_MODEL_INSTANCE_COMMENTS to oldvalue + mySeparatorSign + elementId.
Then I duplicate an existing ViewSchedule.
If it doesn't contain a ScheduleField for the parameter yet, I add this.
After that, I can analyze each row, splitting the value of the comments cell by mySeparatorSign to get the ElementId.
Finally, I rollback the Transaction.
In fact, I used two Transactions inside a TransactionGroup.
That's all.
Of course you could add another parameter to hold the ElementId.IntegerValue and use this one instead of hijacking the comments parameter.
So I was taking the route of creating my own parameter to hold the Element.UniqueId. Are you saying I can't use a new parameter in this way and add it to the Schedule as a column? (The new parameter type I created was of ParameterType.Text, so I'm not sure why when I check the bodySection.GetCellType() for this new column it returns CellType.Parameter, but it does.)
Here is the code that creates the parameter, fills it with each element's UniqueId and inserts it as a new field in the schedule:
public static ViewSchedule createTempSchedule( ViewSchedule origVs, int scheduleFieldIdInt, out Guid idParamGuid, out ScheduleField vsSF )
{
Document doc = origVs.Document;
idParamGuid = Guid.Empty;
vsSF = null;
//duplicate the schedule so that the original is not modified
ElementId newVsId = origVs.Duplicate( ViewDuplicateOption.Duplicate );
ViewSchedule vs = doc.GetElement( newVsId ) as ViewSchedule;
//get the category
CategorySet cs = new CategorySet();
Category cat = doc.Settings.Categories.get_Item( (BuiltInCategory)vs.Definition.CategoryId.IntegerValue );
cs.Insert( cat );
//take the first element of the schedule's category and either get or create the uniqueId parameter
string uniqueIdParamName = "Schedule_Unique_Id";
FilteredElementCollector catFec = new FilteredElementCollector( doc ).OfCategory( (BuiltInCategory)cat.Id.IntegerValue).WhereElementIsNotElementType();
Element testElem = catFec.ToList<Element>()[ 0 ];
if (testElem.get_Parameter( uniqueIdParamName ) == null)
{
idParamGuid = RawCreateProjectParameter( doc.Application, uniqueIdParamName, ParameterType.Text, false, cs, BuiltInParameterGroup.PG_TEXT, true );
}
else
{
idParamGuid = testElem.get_Parameter( uniqueIdParamName ).GUID;
}
foreach (Element elem in catFec)
{
elem.get_Parameter( idParamGuid ).Set( elem.UniqueId );
}
//add uniqueId to the schedule as a new field (column)
SchedulableField ableSf = null;
foreach (SchedulableField thisSf in vs.Definition.GetSchedulableFields())
{
if (thisSf.GetName( doc ).Equals( uniqueIdParamName ))
{
ableSf = thisSf;
break;
}
}
if (ableSf == null) //extra precaution
{
TaskDialog.Show( "Revit", "Didn't find new idParam as Schedulable Field" );
return null;
}
try
{
vs.Definition.InsertField(( ableSf, 0 );
}
catch { }
//remove all other fields except the one with the calculated value in it
for (int i = vs.Definition.GetFieldCount() - 1; i > 0; i--)
{
ScheduleField sf = vs.Definition.GetField( i );
if (sf.FieldId.IntegerValue.Equals( scheduleFieldIdInt ))
{
vsSF = sf;
}
else
{
vs.Definition.RemoveField( sf.FieldId );
}
}
vs.RefreshData();
return vs;
}
Oh, it just occurred to me that GetCellType returns CellType.Parameter because it is a parameter in the cell, duh. I was thinking of it as the type of what the parameter is holding or the type of the data that is displayed in the column which in this case my parameter was set up as Text.
This is of course neither here nor there. I still need to understand what I'm doing wrong in general with my code as I'm unable to get the UniqueId back out of the TableData row that I wrote it into.
Hi,
yes, I did so, but I hadn't time (and will) to look after it yet.
Revitalizer
Well I solved my problems although I'm not 100% sure why I had the problems, but here was the cause:
ViewSchedule vsTemp = createTempSchedule( vs, kvp.Key, out idParamGuid, out targetFieldCol, out vsSF );
var tblData = vsTemp.GetTableData();
var bodySection = tblData.GetSectionData( SectionType.Body );
I was using methods off of the bodySection variable above which yeilds different results than methods off of the ViewSchedule for the bodySection.
So this
bodySection.GetCellText( iBodyRow, bodySection.FirstColumnNumber );
yields different results than
vsTemp.GetCellText( SectionType.Body, iBodyRow, bodySection.FirstColumnNumber );
(The last line above is the one that works correctly.)
Several other methods off of bodySection yielded results that I found unexpected, and caused all kinds of trouble for me.