KennanChan / Revit.Async

Use task-based asynchronous pattern (TAP) to run Revit API code from any execution context.
MIT License
223 stars 51 forks source link

RevitTask.RunAsync() returns before Revit #19

Closed RyanPatrickDaley closed 1 year ago

RyanPatrickDaley commented 1 year ago

The await RevitTask.RunAsync() does not seem to wait for Revit to finish. In the below sample method, RevitTask.RunAsync() returns "Jimmy" before the Selection is set in the ActiveUiDocument. So my MessageBox shows "jimmy" before the selection is made. I'm not sure why this would be the case.

private async void SelectInRevit()
        {
            var myString = await RevitTask.RunAsync(
                app =>
                {
                    app.ActiveUIDocument.Selection.SetElementIds(SelectedFam.ElementIds);
                    return "jimmy"; 
                });
            MessageBox.Show($"{myString}");
        }
KennanChan commented 1 year ago

How about calling document.Regenerate() right after setting selected elements.

RyanPatrickDaley commented 1 year ago

How about calling document.Regenerate() right after setting selected elements.

So, when I simply try to regenerate the document, I get an error.

private async void SelectInRevit()
{
    if(SelectedFam != null)
    {
        var myString = await RevitTask.RunAsync(
            app =>
            {
                app.ActiveUIDocument.Selection.SetElementIds(SelectedFam.ElementIds);
                app.ActiveUIDocument.Document.Regenerate();
                return "Jimmy";
            });
    }            
}

Autodesk.Revit.Exceptions.InvalidOperationException: 'Modification of the document is forbidden. Typically, this is because there is no open transaction; consult documentation for Document.IsModified for other possible causes.'

I'm guessing I would need to open a transaction, and run the RevitTask.RunAsync() inside of the Transaction using statement.

KennanChan commented 1 year ago

How about calling document.Regenerate() right after setting selected elements.

Autodesk.Revit.Exceptions.InvalidOperationException: 'Modification of the document is forbidden. Typically, this is because there is no open transaction; consult documentation for Document.IsModified for other possible causes.'

I'm guessing I would need to open a transaction, and run the RevitTask.RunAsync() inside of the Transaction using statement.

Open transaction inside RevitTask.RunAsync()

RyanPatrickDaley commented 1 year ago

Okay, this is an interested suggestion to include a doc.Regenerate() call inside of a Transaction because the API docs say that .Regenerate() is automatically called when a transaction is committed https://www.revitapidocs.com/2015/22468e2c-9772-8478-0816-c9759aa43428.htm

But in any case, it still doesn't seem to await the Revit part of the method to finish. It returns "Jimmy" and continues.

private async void SelectInRevit()
{
    if(SelectedFam != null)
    {
        var myString = await RevitTask.RunAsync(
            app =>
            {
                using (Transaction t = new Transaction(app.ActiveUIDocument.Document, "SettingSelected"))
                {
                    t.Start("SettingSelected");
                    app.ActiveUIDocument.Selection.SetElementIds(SelectedFam.ElementIds);
                    app.ActiveUIDocument.Document.Regenerate(); 
                    t.Commit();
                }                            
                return "Jimmy";
            });
        myString += " Boy";
    }               
}
KennanChan commented 1 year ago

The Selection.SetElementIds() might be async internally although it returns void. RevitTask doesn't aware of that and just returns when the api call finishes. You might need to find another way to check if the elements are visually selected to continue.

KennanChan commented 1 year ago

You can try to write a pure external event handler to test the code to see if the issue still exists

KennanChan commented 1 year ago

I think I can close this issue. You can submit a new one if the issue persists.