Running Revit asynchronously and updating form after task completed

Running Revit asynchronously and updating form after task completed

jjesusdelpino
Advocate Advocate
3,571 Views
9 Replies
Message 1 of 10

Running Revit asynchronously and updating form after task completed

jjesusdelpino
Advocate
Advocate

Hi forum

 

First of all, I want to clarify Im aware of the plenty of posts here and in Jeremy´s blog similar to this topic. I have tried everything that I have readed and I come here just to see if there´s something Im missing before giving up completely and accept that this cant be done in my concrete case. Also I got the feeling that the problem may not be the tipical Out of API context thing.

 

What Im trying to do is the following:

1. Open a form1 modeless dialog (show some info about the model).

2. Open a form2 modal dialog.

3. Change the Revit document at this point (get views from other document).

4. Close form2.

5. See form1 with the changes applied.

 

My first try was with IExternalEvents. I managed to make this work except for step 5. My last approach has been with the library https://github.com/KennanChan/Revit.Async wich make the work done the same way that external events. In step 3 im capturing the RevitServices.application in a Shared static class, so I can use it later in the method app.OpenDocumentfile(). While im not convinced about this workflow, it is in fact working in that part so Im convinced that thats not the problem here.

 

I have simplified the code to make a reproducible case for this topic. I think that the best and fastest way to show it to you is attaching the .sln ready to run instead of pasting the code which is a little too large. Running the .sln and debugging will do:

 

1. Open the form1 normally showing the info

2. Click button and open form2.

3. Click button in form2 and make changes to the document (ie. event is raised and finished correctly).

4. Close form2 .

5. Show form1 but changes are not applied despite of coding " updateForm1() or this.Refresh();

 

If the problem were that IExternalEvent cant be triggered on time, then it would be ok. I mean, I have read all Jeremy´s post and its clear that you cant exactly control the execution time for this actions. But what bothers me its that the ExternalEvent seems to finish properly. In fact the changes in the model are done. But its the updating of form1 what doesnt take consideration of this changes and thats why I ask here.

 

Help appeciated. Thanks. Regards.

 

PD: Im using Revit 2019.

0 Likes
Accepted solutions (1)
3,572 Views
9 Replies
Replies (9)
Message 2 of 10

jeremytammik
Autodesk
Autodesk

Yes, that may be a little bit tricky.

 

However, I can guarantee that it is possible.

 

I hope this helps.

 

Cheers,

 

Jeremy

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes
Message 3 of 10

jjesusdelpino
Advocate
Advocate
Accepted solution

Thank you so much for you anwser Jeremy. 

 

In case someone have a similar problem, how I finally managed to solve this is with the next workflow:

 

- While calling to my main form, create an instance of it in an static shared class.

- Call the update method of my main form from inside the ExternalEvent (once transaction is closed) throught the static shared class.

 

This may be problematic or have other programatic considerations but until now this is how is working for me.

 

Regards.

0 Likes
Message 4 of 10

jeremytammik
Autodesk
Autodesk

Congratulations on solving it so fast after all!

 

That sounds quite sensible. 

 

Please test it thoroughly.

 

Good luck!

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes
Message 5 of 10

jjesusdelpino
Advocate
Advocate

Thanks! The abstraction of storing an instance of a form its only 2 lines of code but that approach hadn´t come to my mind until now.

 

Regards.

0 Likes
Message 6 of 10

sroswurm4GJQU
Advocate
Advocate

Thank you so much for posting this!!!!  I've been struggling all day with a nearly identical difficulty.  I'm using a form button click event to execute a method, which in turn raises an external event Execute().  Try as I might, I could not find a way to make the form refresh based on the new model information changed by the external event.  I could do it with a separate click event, but when I invoked the refresh command inside the original click event, the form refresh would always execute before the external event was fired.  

 

Passing a reference to the main form instance into the external event and calling the form refresh command inside the Execute() method works perfectly.  I'll review it from several angles to make sure it doesn't do anything unexpected, but it seems to be a great solution to a stubborn problem.  Thanks again!!!

0 Likes
Message 7 of 10

MiguelVJC82W
Enthusiast
Enthusiast

Do you have an example of your updated working code?

0 Likes
Message 8 of 10

Kennan.Chen
Advocate
Advocate

I think the problem is, the CopyViews.Execute method should make the caller acknowledged when the command has been finished.

I don't think the CopyViews class should implement the System.Window.Input.ICommand interface whose Execute method returns void. BTW, The System.Window.Input.ICommand interface works better in a WPF application than a WinForm application.

So just remove the ICommand interface and change the Execute method to return a Task. In Form2, wait for the CopyViews.Execute method and then close Form2.

    public class CopyViews
    {
        public async Task Execute(object parameter)
        {
            await RevitTask.RunAsync(async app =>
            {
                // revit api logic
            });
        }
    }

    public partial class Form2 : System.Windows.Forms.Form
    {


        public int numero;

        public Form2()
        {

            InitializeComponent();
        }

        private async void BTN_CopyElements_Click(object sender, EventArgs e)
        {
            if (true)
            {
                CopyViews MyCopyViewsMethod = new CopyViews();
                await MyCopyViewsMethod.Execute(numero);

                this.Close();
            }
        }
    }

I believe a good knowledge of task-based asynchronous pattern(TAP) helps a lot when writing asynchronous .net code.

I personally gained a deep understanding of TAP through What happens in an async method which I already recommended in the Revit.Async repository

0 Likes
Message 9 of 10

ahmed.elhawary73
Advocate
Advocate

Hello @jjesusdelpino

Please if you can help, have a look in the link below, if it's the same issue, or if you can help anyway.

 

Modeless WPF Behavior understanding with await & async 

0 Likes
Message 10 of 10

jeremy_tammik
Alumni
Alumni

I answered your question in the other thread that you pointed out.

   

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
0 Likes