Calling Revit command from chromium browser.

Calling Revit command from chromium browser.

Andrej.Licanin
Advocate Advocate
726 Views
3 Replies
Message 1 of 4

Calling Revit command from chromium browser.

Andrej.Licanin
Advocate
Advocate

This is another guide on chromium browser using cef sharp. Hope some one finds it usefull.
This is a continuation of this post : Solved: Simple WPF with a chromium browser guide - Autodesk Community - Revit Products

 

Basicly what I wanted was for a button in the browser (on a webpage) to trigger a command in revit. This works by "binding" a javascript method to a c# object and its method. In the Javascript we await for the object and call its function.

 

So lets make a dummy object for binding and a method in it. In order to call a Revit method it will need a reference to an external event handler and its event. 

 

 

 

 

   public class BoundObject
   {

       public int Add(int a, int b)
       {
           ExtApp.handler.a = a;
           ExtApp.handler.b = b;
           ExtApp.testEvent.Raise();

           return a+b;
       }
   }

 

 

 

The event and its handler are saved in the External app as static for ease of access.

 

 

 

  internal class ExtApp : IExternalApplication
  {
      public static IExternalApplication MyApp;
      public static ChromiumWebBrowser browser;
      public static ExternalEvent testEvent;
      public static MyEvent handler;
      public Result OnShutdown(UIControlledApplication application)
      {
         // Cef.Shutdown();
          return Result.Succeeded;
      }

      public Result OnStartup(UIControlledApplication application)
      {
          MyApp = this;
          //code for making a button
         
          handler = new MyEvent();
          testEvent= ExternalEvent.Create(handler);


          return Result.Succeeded;
      }
  }

 

 

 

In the wpf the browser is embeded like this

 

 

 

 

<Window x:Class="RevitTestProject.TestWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:local="clr-namespace:RevitTestProject"
        xmlns:cef="clr-namespace:CefSharp.Wpf;assembly=CefSharp.Wpf"
        mc:Ignorable="d"
        Width="1000" Height="500">
    <Grid Background="PapayaWhip">

        <cef:ChromiumWebBrowser Name="ChromiumBrowser" Address="http://www.google.com" Width="900" Height="450"  />
    </Grid>
</Window>

 

 

 

 

and the code behind  of the window is :

 

 

 

 

        public TestWindow()
        {

 
            InitializeComponent();
            ChromiumBrowser.Address = "https://www.google.com";
            ChromiumBrowser.Address = "C:\\Users\\XXX\\Desktop\\index.html";
            BoundObject bo = new BoundObject();
            ChromiumBrowser.JavascriptObjectRepository.Register("boundAsync", bo, true, BindingOptions.DefaultBinder);
          

        }

        public void Dispose()
        {
            this.Dispose();
        }

 

So to use it make an index.html and make the path to it in the browser address.

 

 The Test webpage look like this:

 

 

 

<html>
<head>
    <title>Bridge Test</title>
    <!-- <script src="script.js"></script> -->
    <script type="text/javascript">
     async function callCSharpAction() {
        await CefSharp.BindObjectAsync("boundAsync");

        boundAsync.add(16, 2);
    }
    </script>
</head>
<body>
    <button id="action1" onclick="callCSharpAction()">Action 1</button>
    <button id="action2" onclick="alert('Button is working')">Action 2</button>
    <button id="action3">Action 3</button>
</body>
</html>

 

 

 

The handler code:

 

 

 

  internal class MyEvent : IExternalEventHandler
  {
      public int a;
      public int b;
      public void Execute(UIApplication app)
      {
          TaskDialog.Show("yoyoy", "data is "+a.ToString()+" and "+b.ToString()+".");
      }

      public string GetName()
      {
          return "YOYOOY";
      }
  }

 

 

 

 

 

727 Views
3 Replies
Replies (3)
Message 2 of 4

jeremy_tammik
Alumni
Alumni

Thank you very much indeed for a very nice example of implementing a minimal external event and using it to call Revit from outside, from a modeless context. This is a perfect fit for The Building Coder topic group:

  

  

I'll gladly add it to the blog next week, if I may. Happy weekend to you!

  

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
Message 3 of 4

Andrej.Licanin
Advocate
Advocate

Sure Jeremy, id love to see what people can do with it 🙂

Message 4 of 4

Andrej.Licanin
Advocate
Advocate

To make a callback from c# function to the browser, you just need an instance of the browser, and a function in the javascript code that will be called.

 

here is an edited index.html

<html>
<head>
    <title>Bridge Test</title>
    <!-- <script src="script.js"></script> -->
    <script type="text/javascript">
     async function callCSharpAction() {
        await CefSharp.BindObjectAsync("boundAsync");

        boundAsync.add(16, 2);
    }


    function showAlert(arg1) {
        // Your JavaScript logic here
        alert("Function called with arguments: " + arg1);
        return ;
    }
    </script>
</head>
<body>
    <button id="action1" onclick="callCSharpAction()">Action 1</button>
    <button id="action2" onclick="alert('Button is working')">Action 2</button>
    <button id="action3">Action 3</button>
</body>
</html>

 

and in our bound class we save a instance to the browser so we can use it on command

    public class BoundObject
    {
        public int aS;
        public int bS;
        internal ChromiumWebBrowser browser;

        public void CallCSharpMethod()
        {
            MessageBox.Show("C# method called!");
            // Add more code here as needed
        }
        public int Add(int a, int b)
        {
            ExtApp.handler.a = a;
            ExtApp.handler.b = b;
            ExtApp.testEvent.Raise();

            return a+b;

        }

        public int SendSomeDataFromLocal(int a)
        {
            browser.ExecuteScriptAsync("showAlert("+a.ToString()+")");
            return a;
        }
    }

i passed it when i created the browser in the window codebehind.

public TestWindow()
{

 
    InitializeComponent();
    ChromiumBrowser.Address = "https://www.google.com";
    ChromiumBrowser.Address = "C:\\Users\\XXX\\Desktop\\index.html";
    BoundObject bo = new BoundObject();
    //ExtApp.boundObj = bo;
    bo.browser = ChromiumBrowser;
    ChromiumBrowser.JavascriptObjectRepository.Register("boundAsync", bo, true, BindingOptions.DefaultBinder);
  

}

 

finally you can call it from revit 

 

   public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
   {
       ExtApp.boundObj.SendSomeDataFromLocal(999);


       return Result.Succeeded;
   }

 

this concludes a round trip from the browser and back. I hope anyone reading this finds it usefull.

 

0 Likes