Announcements
Attention for Customers without Multi-Factor Authentication or Single Sign-On - OTP Verification rolls out April 2025. Read all about it here.

How to get UIApplication from IExternalApplication

cedemax
Explorer

How to get UIApplication from IExternalApplication

cedemax
Explorer
Explorer

Hi!

 

Following this post i tried to implement it  in an External Application as they suggested. However i don't understand how i can get the UIApplication from the UIControllApplication. After some googling this seems impossible, instead one is supposed to get it from the "object sender" in the PanelEvent class. When debugging the code it shows PanelEvent class object sender type to be RvtRibbonTab, which when cast to Application returns null and cant thus be used to create an UIApplication. What am I missing? 

0 Likes
Reply
Accepted solutions (2)
10,069 Views
6 Replies
Replies (6)

Mustafa.Salaheldin
Collaborator
Collaborator
Accepted solution

You should use the idle event.

 

Try the following code and if it satisfies your needs don't forget to mark the rply as an answer:

 

#region Namespaces

using System;
using System.Text;
using System.Linq;
using System.Xml;
using System.Reflection;
using System.ComponentModel;
using System.Collections;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media.Imaging;
using System.Windows.Forms;
using System.IO;

using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.Attributes;

using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Events;
using Autodesk.Revit.DB.Architecture;
using Autodesk.Revit.DB.Structure;
using Autodesk.Revit.DB.Mechanical;
using Autodesk.Revit.DB.Electrical;
using Autodesk.Revit.DB.Plumbing;

using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using Autodesk.Revit.UI.Events;

//using Autodesk.Revit.Collections;
using Autodesk.Revit.Exceptions;
using Autodesk.Revit.Utility;

using RvtApplication = Autodesk.Revit.ApplicationServices.Application;
using RvtDocument = Autodesk.Revit.DB.Document;

#endregion

namespace RevitAddinCS2
{
    [Transaction(TransactionMode.Manual)] 
    [Regeneration(RegenerationOption.Manual)] 
    public class ExtApp : IExternalApplication
    {
        #region Cached Variables

        public static UIControlledApplication _cachedUiCtrApp;
        #endregion

        #region IExternalApplication Members

        public Result OnStartup(UIControlledApplication uiCtrlApp)
        {
            _cachedUiCtrApp = uiCtrlApp;

            try
            {
                //TODO: add you code below.
                _cachedUiCtrApp.Idling += OnIdling;

                return Result.Succeeded;
            }
            catch (Exception ex)
            {
                MessageBox.Show( ex.ToString() );
                return Result.Failed;
            }
        }

        private void OnIdling(object sender, IdlingEventArgs e)
        {
            _cachedUiCtrApp.Idling -= OnIdling;

            UIApplication uiapp = sender as UIApplication;

            if (uiapp != null)
            {
                UIDocument uidoc = uiapp.ActiveUIDocument;
                Document doc = uidoc.Document;
            }
        }

        public Result OnShutdown(UIControlledApplication uiApp)
        {
            try
            {
                //TODO: add you code below.


                return Result.Succeeded;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
                return Result.Failed;
            }
        }

        #endregion

    }
}

¯\_(ツ)_/¯
Let it work like a charm.

Mustafa Salaheldin


EESignature




Digital Integration Manager, DuPod

Facebook | Twitter | LinkedIn

cedemax
Explorer
Explorer

Thank you! This was exactly what i wanted. I added the UIApplication as another cached variable in order to access it from the other event. Thank you again!

0 Likes

Anonymous
Not applicable

Can you do this for the Failure Handling Event?  I keep getting a null reference for the uiapp when trying to get this from the Failure Handling event.  When debugging the sender appears to be an ApplicationServices.Application object.

void ControlledApplication_FailuresProcessing(object sender, Autodesk.Revit.DB.Events.FailuresProcessingEventArgs e)
        {
            List<ElementId> oFailedElements = new List<ElementId>();
            UIApplication uiapp = sender as UIApplication;

            //My Failure Handling Code is here.
        }
0 Likes

Chuong.Ho
Advocate
Advocate

Try some :

 public Result OnStartup(UIControlledApplication application)
    {
        application.ControlledApplication.ApplicationInitialized  += test;
    }

    private void test(object sender, ApplicationInitializedEventArgs e)
    {
        if (sender is Application application)
        {
            var uiApp = new UIApplication(application);
            // something 
        }
    }

Chuong Ho

EESignature

ricaun
Advisor
Advisor
Accepted solution

Actually you can access the internal UIApplication inside the UIControlledApplication using some reflation. So you don't need to wait for the event.

 

public Result OnStartup(UIControlledApplication application)
{
    UIApplication uiapp = application.GetUIApplication();
    string userName = uiapp.Application.Username;
    return Result.Succeeded;
}

 

Here is the extension code.

/// <summary>
/// Get <see cref="Autodesk.Revit.UI.UIApplication"/> using the <paramref name="application"/>
/// </summary>
/// <param name="application">Revit UIApplication</param>
public static UIApplication GetUIApplication(this UIControlledApplication application)
{
    var type = typeof(UIControlledApplication);

    var propertie = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic)
        .FirstOrDefault(e => e.FieldType == typeof(UIApplication));

    return propertie?.GetValue(application) as UIApplication;
}

 

You can find the whole file extension below with the extension to convert UIApplication to UIControlledApplication as well.

 

 

Luiz Henrique Cassettari

ricaun.com - Revit API Developer

AppLoader EasyConduit WireInConduit ConduitMaterial CircuitName ElectricalUtils

Chuong.Ho
Advocate
Advocate

@ricaun , that is awesome solution.

 

Chuong Ho

EESignature