Hi Matt,
I think we are getting very close to making it work.
Here is my updated code:
namespace RevitElementRenumber2017
{
[Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
[Autodesk.Revit.Attributes.Regeneration(Autodesk.Revit.Attributes.RegenerationOption.Manual)]
[Autodesk.Revit.Attributes.Journaling(Autodesk.Revit.Attributes.JournalingMode.NoCommandData)]
public class RevitElementRenumber2017 : IExternalCommand
{
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
try
{
var menu = new ElementRenumberMenu(commandData) {StartPosition = FormStartPosition.CenterScreen};//Publisher
menu.Show(); //menu.Show would be modaless; modaless form starts a separate thread and transaction.manual will be errored out!
}
catch (Exception)
{
return Result.Failed;
}
return Result.Succeeded;
}
}
}
menu.Show() displays the form and when user clicks the PickElement button on the form, the btn_click event does this:
private void btnPickElement_Click(object sender, EventArgs e)
{
Visible = false;
var UIErrorFound = ErrorChecking();
if (UIErrorFound) return;
SelectedPrefix = txtPrefix.Text;
SequenceStartValue = txtSequenceStartingPoint.Text.Trim();
SelectedCategory = cbCategory.SelectedItem.ToString().Trim();
switch (SelectedCategory)
{
case "Plumbing Fixtures":
case "Mechanical Equipment":
RenumberSingleElement(cmdData);
break;
case "Viewports":
The RenumberSingleElement(cmdData) has been updated to what you suggested and it looks like this now:
private bool RenumberSingleElement(ExternalCommandData commandData)
{
UIDocument uidoc = commandData.Application.ActiveUIDocument;
Document dbdoc = uidoc.Document;
int startValue;
int.TryParse(SequenceStartValue, out startValue);
var counter = startValue;
bool proceed = true;
using (var t1 = new TransactionGroup(dbdoc, "Select Single Element"))
{
t1.Start();
while (proceed)
{
Reference SelectedElement;
try
{
SelectedElement = uidoc.Selection.PickObject(ObjectType.Element, new GenericSelectionFilter(SelectedCategory), "Select an element to renumber. Press ESC to exit renumbering.");
}
catch (OperationCanceledException ex)
{
break;
}
try
{
using (var t2 = new Transaction(dbdoc, "Renumber Single Element"))
{
t2.Start();
if (string.IsNullOrEmpty(SelectedPrefix))
{
Parameter p = GetParameterForReference(dbdoc, SelectedElement);
var newLabel = counter.ToString();
SetParameterToValue(dbdoc, SelectedElement, p, newLabel);
counter++;
}
else
{
Parameter p = GetParameterForReference(dbdoc, SelectedElement);
var newLabel = String.Format("{0}{1}", SelectedPrefix, counter);
SetParameterToValue(dbdoc, SelectedElement, p, newLabel);
counter++;
}
var TransactionResult = t2.Commit();
if (TransactionResult == TransactionStatus.Committed) return false;
}
}
catch (Exception ex)
{
proceed = false;
}
}
t1.Assimilate();
}
return true;
}
The current issue is whenever it hits the inner transaction t2, it errored out on the t2.Start() showing error "Starting a transaction from an external application running outside of API context is not allowed, which was why I used the External Event but the External Event won't fire inside a while loop but worked great if the user selects ALL the elements at once, then External Event is used to do db update but that does not offer the instantaneous screen update. Instantaneous updates to me means when "pressing ESC on the updated param values on screen" WILL NOT reset the parameter values back to before-change.
So may be I am NOT setting the transaction mode correctly or the transactions in proper sequence. What did I miss?
Thanks again for your patience and expertise.
Shirley