Using Eto.Forms within a Cocoa app?

295 views
Skip to first unread message

Michael Bevin

unread,
Sep 23, 2014, 12:02:52 PM9/23/14
to eto-...@googlegroups.com
Is it possible to use specific Eto.Forms controls, within an app that is otherwise using native controls. This would make it much more appealing to us in terms of initially trying out replacing specific controls with Eto.Forms ones, rather than having to make the decision to fully commit to rewriting the UI from scratch in Eto.Forms. 

And if the answer to this question is yes, does anyone know of any examples of a project doing this?

curtis

unread,
Sep 23, 2014, 3:20:47 PM9/23/14
to eto-...@googlegroups.com

You can certainly do this, yes. There are no open source projects that I know that are using this, but this functionality is being used.

To do this, just attach the application at the startup of your app or before you use any Eto.Forms code (using develop branch):

// do this only once
var platformType = Platforms.Mac; // select the appropriate platform to run here..

new Application(platformType).Attach(); // attach a new application to the running application

// now, we can call eto.forms code
var form = new Form { Title = "Hello", Content = new Label { Text = "World" } };
form
.Show();

Note that if you are intending on using Eto.Forms in a native objective-c cocoa app, then you'll have to embed mono in your application first.

Hope this helps!

Curtis.

Michael Bevin

unread,
Sep 24, 2014, 6:36:51 AM9/24/14
to eto-...@googlegroups.com
Hi, thanks for the quick reply. I'm doing a pure C# app using Xamarin.Mac ....

In your example, you're creating a 'Form', which I understand is a window. I'm also in interested in whether for example I could use specific components within an existing cocoa Window, and if so how, and what gotchas might be involved with that? For example replacing a table-view within my main window with the Eto.forms' equivalent ...? 

curtis

unread,
Sep 26, 2014, 5:19:08 PM9/26/14
to eto-...@googlegroups.com
Hi Michael,

Yes, you can do that as well.  You'll have to reference the correct platform assembly (e.g. Eto.XamMac), and then do something like this:

using Eto.Mac.Forms;

var etoGrid = new Eto.Forms.GridView();

etoGrid
.AttachNative(); // prepares to attach the control natively
NSView controlView = etoGrid.GetContainerView(); // get the NSView that contains the control

// add controlView to your app however you like

This isn't the prettiest code, but it should work.  On windows, it's GetContainerControl(), and gtk uses GetContainerWidget().  If this is a very common scenario, we can streamline this a bit better.  e.g. make each platform assembly define extension methods in the Eto.Forms namespace with consistent naming.  That way, you could just reference the platform assembly and then call myControl.GetNative().

Hope this helps!
Curtis.

Michael Bevin

unread,
Sep 29, 2014, 8:36:31 PM9/29/14
to eto-...@googlegroups.com
Right, thanks for that. That helps. I imagine it is indeed a reasonably common scenario, similarly to the following question - both being examples of common things one wants to be able to do in the process of migrating an existing app to Eto.Forms

So yeah, the other question is, I'm also needing to do the reverse of this - that is, if one has some custom class (i.e. that inherits NSView, i.e. MyCustomNSTableView), which handles events and everything within itself already ... and one wants to simply use that somewhere where an Eto Control is expected, i.e. something like:
   var myTable = new MyCustomNSTableView(); 
   MainForm.Control = myTable;

In doing this, we're not worrying about cross-platformness, the aim is just wrapping something existing quickly to get it to work initially along with Eto.Forms code, rather than creating some new Eto.Forms general purpose control with implementations on all platforms etc, as we're simply in the process of adapting an existing Mono/Xam.Mac app to Eto.Forms.

Is that possible without too much work? I looked at the Custom-Platform-Controls page on the wiki - https://github.com/picoe/Eto/wiki/Custom-Platform-Controls - however the code there appears out of date as for example MacControl requires 3 not 2 parameters, and IControl no longer appears to exist ... I also looked at MacControl + MacView + IMacControl, but from all that it wasn't clear what a simple approach is to doing a generic 'Convert this NSView to Eto Control'?

curtis

unread,
Oct 1, 2014, 3:51:11 PM10/1/14
to eto-...@googlegroups.com
Hi Michael,

That is certainly possible, but not really easy to do.  I will look at adding the ability to do this more easily for all platforms, but for now, you could create a Control subclass that takes an IHandler as a parameter (passing it to the base class constructor), then create a new handler implementation that  can take an NSView parameter.

e.g. (I'm just typing this here, so it may or may not work 100%):

// wrapper control class
public class NativeControl : Control
{
 
public NativeControl(IHandler handler) : base(handler) { }
 
public new interface IHandler : Control.IHandler { }
}


// in your mac app:
public class NativeControlHandler : MacControl<NSView, NativeControl, NativeControl.ICallback>, NativeControl.IHandler
{
 
public NativeControlHandler(NSView view) { Control = view; }
}

// then use it like:
var myControl = new NativeControl(new NativeControlHandler(myNativeNSView));

myPanel
.Content = myControl;

Hope this helps!
Curtis.

Michael Bevin

unread,
Oct 3, 2014, 6:12:17 AM10/3/14
to eto-...@googlegroups.com
Yeah, I imagine that definitely this ability to in both directions between native + eto.forms controls is generally very useful for anyone considering using eto.forms but starting from an existing codebase or worried about hitting limits and being able to 'go native' with parts, etc .... so any simplification of that process can't hurt. But what you write should give me enough to go on for now, thanks.

curtis

unread,
Oct 18, 2014, 3:37:37 PM10/18/14
to eto-...@googlegroups.com
Hi Michael,

I've added samples for doing both embedding Eto in an existing app, or embedding existing native controls in Eto.


I've also created examples for Gtk, Wpf, and WinForms.

Cheers!
Curtis.

Jose Bonilla

unread,
Oct 19, 2014, 10:32:38 PM10/19/14
to eto-...@googlegroups.com
Thanks for posting such a great guide. Please let me know if it is posible to achieve what I am trying to do:

1. I have a windows forms application, that runs really well on Windows, fairly in Linux and really bad in Mac. I noticed the main issues are the Dialogs so I would like to preserve WinForms and replace all the dialogs to native ones, but still running a WinForms application in all platforms.

2. I tried the WinForms sample, but it shows the Win Dialogs instead of native ones in Linux or Mac. I am starting to think that this guide is for calling always one platform controls but using Eto coding. 

The firts though I had with "embedding" was calling native controls inside the same aplication, not just coding Eto style. Maybe I am misunderstanding the concept of this.

How can I call Eto Dialogs with native look inside an existing application?

I already tried the following:

// initialize eto forms after native app is initialized (no platform)
new Eto.Forms.Application().Attach();

//inside the form in a WinForms Button
var dialog = new Eto.Forms.OpenFileDialog();            
dialog.ShowDialog(null); //can't attach to an Eto.Control.

But whenever I push the button on Linux or Mac, it freezes or crashes.

Please let me know if you need some working sample.

By the way, you are doing a great job!

curtis

unread,
Oct 19, 2014, 11:28:25 PM10/19/14
to eto-...@googlegroups.com
Hi Jose,

You *should* be able to do this, with some work:

1) Cocoa requires you run in an .app bundle, so you'll have to create a MonoMac .app bundle, then instead of creating a cocoa window for your app, create your windows forms based UI.  You could use Eto.Forms for the app startup on MonoMac.

2) To startup the windows forms code, you'll most likely have to do that in a separate thread than the cocoa app, so you'll have two main loops (one for cocoa, one for windows forms), each running in a different thread.

3) You should then be able to use any Eto.Forms code (to show dialogs, forms, etc), though setting the parent of a dialog I'm not sure of, as it'll have to somehow get the Cocoa window handle from the windows forms window.  This may get a bit complicated as the eto.forms code will need to be executed in the main thread, whereas your windows forms code will have to run in the separate thread you created in #2.  Fortunately, you can do this using Invoke() calls pretty easily.

4) You probably won't be able to embed a cocoa/eto control inside of a windows forms control in this scenario though, however if you use a separate Eto.WinForms.Platform instance in your windows-forms thread, this would theoretically work as well.

Hope this helps get you started!  There has been a lot of care put into Eto.Forms to allow for multiple platforms running in various threads for this particular scenario, so it should work well.  However, I have not tested this. 

If you run into issues, let me know - I may be able to put together a little sample that would show how to do this.

Cheers!
Curtis.

Jose Bonilla

unread,
Oct 20, 2014, 12:03:03 AM10/20/14
to eto-...@googlegroups.com
Thanks as always for your soon response.

It would be really helpful some sample code. I think migrating an application should go this way:

4) ...however if you use a separate Eto.WinForms.Platform instance in your windows-forms thread, this would theoretically work as well.

Primarily for WinForms and GTK, that almost work well in all main platforms, and it would be awesome to migrate forms one by one, preserving meanwhile the UI across all the SO's. Maybe following this approach:


"
...added platform-specific code in various places where the native platform would be exposed. For example, contextual menus are now drawn using the native theme, file dialogs are system dialogs, and the Gtk+ behavior and theme has been tuned to be closer to each platform’s guidelines.
"

However, I think Eto.Forms is more mature.

Regards.
Reply all
Reply to author
Forward
0 new messages