Eto.WebView Event Listeners

Hi,

Is there a way to use event listeners within a WebView? For instance if I have a button in my html, can pressing that button trigger a script in python/grasshopper and output values etc. Still trying to wrap my head around the Eto documentation. I notice some event methods but not sure if any of them are what I need.

Jordan.

A while back I hacked something together that kind of did this: https://github.com/fraguada/TestWebUI
There is a basic html/js app with some buttons and a Rhino plugin with an Eto form using WebView that listens to the DocumentLoading event fired when the WebView is navigating to a different page. Here I exploit that event, cause the html/js never actually navigates to another page (navigation is canceled). There are probably less hacky ways to go about it.

1 Like

I was trying another hacky solution of trying to trigger changes in Rhino by listening for Document Title changes but I kept having issues with Rhino being triggered twice - your method saved me so many headaches THANK YOU!!! <3

Bumping this as I have a similar problem. I’m using a webview to load Open Street Maps. With open street maps, when you navigate in the map by scrolling or panning, the url is updated to show the some info about the position of the map. Unfortunately, this doesn’t seem to be triggering any of the events available that I hoped it would.

Does anyone know of a way to get this info when the map is interacted with? Right now the closest I can get is to grab the url when I leave the webview control, but I would like something more responsive. Even the mouse events don’t seem to be triggered unless I am doing something wrong.

1 Like

I’m interested in this as well. Haven’t started testing but will report back if I find anything

Hi Kyle,

Have you tried the OnNavigate event? I’ve been using this with some success this week. It should trigger as your URL updates I would imagine.

Cheers

DK

Yeah that was the one I tried first, but it doesn’t fire during map operations, even though the url changes. I guess there isn’t any actual navigation to a new page, just an update of the url with the new map info, so the event doesn’t get fired.

Thanks Kyle, yeah, I got the page reload and navigate events to work, but I’ve run to a few other issues which are driving me nuts.

I’m going to put up a post about these shortly.

Eto.WebView is kind of cool and kind of not quite right too.

Cheers

DK

The way to do this would be to hook into some javascript event then do something like this (in js): window.location = "myprefix:some-event";, and in the DocumentLoading event, check for the prefix, set e.Cancel = true, and do whatever logic you need there in .NET.

Hope this helps.

I’ve seen from all your past posts that you work with Python as well. Have you figured out a way yet?

Nothing definitive like connecting a button directly to a web action or vice versa but using the .OnNavigatedEvent does one allow to “DoSomething” and you can look at the web URL during that event and do things based on the URL string but that’s not really proper way to do it.

Ah, is there a reason you go for an OnNavigatedEvent rather than an OnDocumentLoadedEvent like @fraguada suggested above? Say, for a slider on a HTML page that I’d like to use in Rhino or Grasshopper.

Because I did hack my way around it a couple hours after and I went with the DocumentLoaded event instead. But I don’t know if it is the “right” way.

I may be misunderstanding the events but I believe DocumentLoaded is called when the url is first loaded right?

OnNavigated allows me to response to anytime the page or url changes

No no, it seems to be called every time a page reloads. Say, you have a slider, it’s called every time the slider is moved. I actually sort of hacked something together yesterday.

import clr
clr.AddReference("Eto")
clr.AddReference("Rhino.UI")
from Eto.Forms import WebView, Form, DynamicLayout
from Eto.Drawing import Size, Padding
import Rhino

class GreenScenarioPanel(Form):
    def __init__(self):
        self.Title = "Green Scenario WebView"
        self.ClientSize = Size(800, 600)

        # HTML content with the slider input
        html = """
        <head>
            <meta http-equiv='X-UA-Compatible' content='IE=edge' />
            <title>Rhino UI</title>
        </head>
        <body>
            <p>Runoff limit
                <input type='range' min='0' max='100' value='50' class='slider' id='runoffLimit'>
            </p>
            <script>
                document.getElementById('runoffLimit').addEventListener('input', function() {
                    let value = document.getElementById('runoffLimit').value;
                    window.location = 'greenscenario:runofflimit?' + value;
                });
            </script>
        </body>
        """

        # Create the WebView control
        self.webview = WebView()
        self.webview.Size = Size(800, 600)
        self.webview.LoadHtml(html)

        # Subscribe to the DocumentLoading event to intercept navigation
        self.webview.DocumentLoading += self.on_document_loading

        # Create a DynamicLayout for the UI
        layout = DynamicLayout(DefaultSpacing=Size(5, 5), Padding=Padding(0))
        layout.AddSeparateRow(self.webview)
        layout.Add(None)
        
        # Set the layout as the content of the form
        self.Content = layout

    def on_document_loading(self, sender, e):
        # Intercept custom scheme (e.g., "greenscenario")
        if e.Uri.Scheme == "greenscenario":
            e.Cancel = True  # Prevent actual navigation
            value = e.Uri.Query.strip('?')  # Get the value from the query string
            self.communicate_with_webview(value)

    def communicate_with_webview(self, value):
        # Log the slider value to the Rhino command line or output panel
        Rhino.RhinoApp.WriteLine("Slider Value: {0}".format(value))

# Show the form
form = GreenScenarioPanel()
form.Show()

It seems to be doing the trick for me. I found somebody working with C# on another forum post, I just tried to convert it to IronPython and it worked.