Update Eto form from another thread

Hi there,

I am trying to update an Eto form from another thread. My main purpose is to populate a dialog with data from an external source that takes about 6-7 seconds to be fetched. I’d like to have a quickly displayed dialog, that is populated after the data is fetched.

I have been using the example below but it results in an exception:

SystemError: The calling thread must be STA, because many UI components require this.

Does anyone know a way to achieve this?

Cheers,
Tim

import thread, time
from threading import Timer

import Rhino.UI
import Eto.Drawing as drawing
import Eto.Forms as forms

class SimpleEtoDialog(forms.Dialog):

    def __init__(self, data):
        self.Title = "Sample Eto Dialog"
        self.ClientSize = drawing.Size(200, 200)
        self.Padding = drawing.Padding(5)
        self.Resizable = False
        
        self.data = data
        
        # build layout
        self.rebuild()

        
    def rebuild(self):
        label = forms.Label()
        label.Text = self.data
        
        self.Content = label    
    
    def getData(self):
        return self.data
        
    def handleClick(self, sender, e):
        
        self.data = 'test data: 789'
        self.rebuild()


def asyncFetch(dialog, *args):
    
    #mimic data fetching with timeout
    time.sleep(2)
    print 'data fetched'
    
    #update dialog with fetched data and rebuild
    dialog.data = 'new data: 456'
    print dialog.getData()
    dialog.rebuild()

def main():
    
    dialog = SimpleEtoDialog('old data: 123')
    
    # start thread to update ui with database data
    thread.start_new_thread(asyncFetch,(dialog,))

    # show model
    dialog.ShowModal(Rhino.UI.RhinoEtoApp.MainWindow)
    
if __name__ == "__main__":
    main()

Hi @timcastelijn,

To perform any actions with the UI classes from a background thread, you can use either Application.Instance.Invoke() or Application.Instance.AsyncInvoke().

In your example, you simply need to call rebuild() like so:

forms.Application.Instance.Invoke(dialog.rebuild)

Hope this helps!

@curtisw , Thanks a lot! have a good weekend