# Eto.Forms: a native-toolkit GUI layer for .NET desktop apps

> Eto.Forms wraps the platform's own widget toolkit behind one C# API, so a single UI codebase can run on WPF, Windows Forms, MonoMac and GTK#. It is a good fit for tooling and internal apps, and a poor fit for anything that needs pixel-identical rendering across platforms.

**picoe/Eto** — Cross platform GUI framework for desktop and mobile applications in .NET

- Repository: https://github.com/picoe/Eto
- Stars: 3,973 · Forks: 348
- Language: C#
- License: NOASSERTION
- Published: 2026-09-23 · Updated: 2026-09-23 · Language: en
- Canonical page: https://hysenlabs.com/projects/picoe-eto

## What Eto.Forms solves, and for whom

A .NET desktop application that has to run on Windows, macOS and Linux normally faces a choice: write the UI three times against WPF, AppKit and GTK#, or pick one toolkit and ship something that looks foreign on the other two. Eto.Forms takes a third route. It defines one widget API in C# and implements it against each platform's native toolkit, so a Button is a real WPF button on Windows and a real GTK# button on Linux. The README describes the goal directly: applications "look and work as a native application on all platforms, using a single UI codebase."

The audience is narrow and identifiable. The repository lists applications built on it, and they are mostly developer tools and domain software rather than consumer products: the MonoGame content pipeline tool, PabloDraw, a chemical process simulator, a technical SEO auditing tool, a genealogy application, and Rhinoceros 3D. That list tells you what the framework is good at. These are applications where the window is a control surface for a bigger engine, where native menus and dialogs matter more than bespoke visual design, and where maintaining three UI layers would be wasted effort.

If your application's value is in its visual identity, Eto.Forms works against you. You get the platform's widgets, which means the platform's look. The framework does not promise identical pixels, and the README does not claim it does.

## How the platform abstraction actually works

Eto.Forms separates the API you program against from the backend that draws it. Your code references Eto.Forms and Eto.Drawing types such as Form, Label and Size. At runtime a platform handler supplies the concrete implementation. The F# example in the README makes this explicit, calling Eto.Platform.Initialize(Eto.Platforms.WinForms) before constructing the application. That call is the seam: swap WinForms for another platform and the same form definition runs against a different toolkit.

The README names the supported desktop backends as Windows Forms, WPF, MonoMac and GTK#, and the repository layout mirrors that split with samples/WinForms/, samples/Wpf/, samples/MacOS/ and samples/Gtk/ directories. The screenshots section attributes each one: Windows via WPF, Mac via MonoMac, Linux via GTK#3.

There is an escape hatch for the parts the abstraction cannot cover. The README states that for advanced scenarios you can wrap your common UI in a larger application that uses each platform's capabilities directly, or write your own high-level controls with a custom implementation per platform. So the model is not "one abstraction to rule everything." It is a shared core with per-platform extensions, and the documentation expects you to use them.

Two details in the README are worth flagging. First, the mobile story: a Mobile/iOS port exists but "is considered incomplete." Second, drawing. Several third-party charting libraries are listed in both a pure Eto.Forms edition and a SkiaSharp edition, which suggests the built-in drawing path and the SkiaSharp path are not interchangeable in capability.

## Installing Eto.Forms and running a first window

The README points to the Quick Start Guide in the project wiki rather than listing install steps, so the exact package set depends on which backend you target. What the repository does show is the shape of a minimal application, and the NuGet badge in the README confirms Eto.Forms is distributed as a NuGet package.

A hello-world form, taken from the README, defines a class inheriting Form and sets three properties: Title, ClientSize and Content.

```csharp
using Eto.Forms;
using Eto.Drawing;

public class MyForm : Form
{
    public MyForm()
    {
        Title = "My Cross-Platform App";
        ClientSize = new Size(200, 200);
        Content = new Label { Text = "Hello World!" };
    }

    [STAThread]
    static void Main()
    {
        new Application().Run(new MyForm());
    }
}
```

Application().Run() starts the platform's message loop and shows the form. Note the [STAThread] attribute on Main: this is a desktop UI entry point, not a console program, and the threading model of the underlying toolkit still applies.

The README also gives an F# variant that shows the platform initialization step explicitly.

```fsharp
open Eto.Drawing
open Eto.Forms

type MyForm() as this =
    inherit Form()
    do
        this.Title      <- "My Cross-Platform App"
        this.ClientSize <- Size (200, 200)
        this.Content    <- new Label(Text = "Hello F# World!")

Eto.Platform.Initialize(Eto.Platforms.WinForms)
let app = new Application()
let form = new MyForm()
form.Show()
```

The F# sample loads a Paket-generated script, .paket/load/eto.platform.windows.fsx, and the README links to the Paket documentation for generating those scripts. If you are not using Paket, that line does not apply to you and you will need the equivalent NuGet reference for your target platform. The README does not spell that out, which is the first place a new user will have to look beyond it.

## Where Eto.Forms is the wrong tool

The clearest limitation is stated by the project itself: the Mobile/iOS port is incomplete. If your roadmap includes a phone or tablet build, Eto.Forms is not the framework to plan around, and the README gives no timeline for changing that.

The second limitation is inherent to the design. Because each backend uses the native toolkit, behavior is only as consistent as the underlying toolkits are. A control that exists with rich behavior on WPF may map to something simpler on GTK#3, or the other way around. The README does not publish a compatibility matrix for widgets across backends. The practical consequence is that you cannot fully validate a UI on one platform and assume the others behave the same way. The repository includes Eto.Test, described as an application to test the functionality of each widget, which is the project's own answer to this problem: you are expected to check per-platform behavior rather than trust the abstraction.

Third, the drawing model splits. The README's third-party library table lists Pure Eto.Forms and SkiaSharp editions as separate packages for ScottPlot, OxyPlot and others. That means a charting or custom-drawing component may require the SkiaSharp path, which is a different dependency and a different rendering route than the pure path. If your application is drawing-heavy, this is a decision you make early, not a detail you discover later.

Finally, the license field for the repository is NOASSERTION, and the repository contains a LICENSE.txt file. The README does not state the license terms. Anyone embedding this in a commercial product should read LICENSE.txt directly rather than infer terms from the framework's permissive reputation.

## How it compares with Avalonia and Uno

The obvious alternatives for cross-platform .NET UI are Avalonia and Uno, and the difference is architectural rather than a matter of feature checklists. Avalonia renders its own widget set rather than delegating to the platform toolkit. The result is that an Avalonia window looks the same on Windows, macOS and Linux, and the team controls the rendering pipeline end to end. Eto.Forms does the opposite: it hands drawing to WPF, MonoMac or GTK#, so a window matches the host platform but the framework cannot guarantee identical output.

That single choice drives everything else. With Eto.Forms you inherit native dialogs, native menus and native text rendering for free, and you inherit the platform's quirks and gaps too. With a self-rendered toolkit you get consistency and control, and you take on the work of matching platform conventions yourself.

Avalonia also has a playground for trying controls in a browser, which is a materially different onboarding experience from Eto.Forms, where the README sends you to a wiki Quick Start and the repository's Eto.Test app. Neither approach is better in the abstract. If your users compare your app side by side with other apps on their machine, Eto.Forms has the advantage. If your designers specify exact spacing and colors and expect them to hold everywhere, a self-rendered toolkit is the more direct route.

Note also that the Eto.Forms README lists WPF and Windows Forms as desktop backends, which means existing WPF or WinForms code is not thrown away: the framework can sit on top of a toolkit you already use on Windows.

## Maintenance, releases and what an upgrade costs

The repository is not archived, and the last push was on 2026-09-21, two days before this writing. That is current activity. The release history shows 2.11.0 on 2026-03-02, preceded by 2.10.2 on 2025-09-26 and 2.10.1 on 2025-09-18. Two releases within eight days in September 2025 followed by a larger jump in March 2026 suggests a patch-then-minor rhythm rather than continuous churn. The default branch is develop, and the README badges point at both NuGet for stable packages and MyGet for prerelease builds, so there is a documented channel for testing unreleased code.

The upgrade cost is not the framework itself, which is a library you reference. It is the backend matrix. A change that touches a shared control can behave differently on WPF, Windows Forms, MonoMac and GTK#3, and the README does not describe a compatibility policy across them. The repository's build, test and samples directories, plus the Eto.Test application, are the tools available for checking that a bump did not break one platform. Treating a version bump as a single-platform change is the mistake to avoid.

On licensing, the repository's license field reads NOASSERTION and a LICENSE.txt is present at the top level. The README does not summarize the terms. If you are shipping a closed-source product, read that file before you depend on the framework, and do not assume terms from the project's public visibility.

## Conclusion

Adopt Eto.Forms if you maintain a .NET desktop tool that has to look native on Windows, macOS and Linux without three separate UI codebases, and if you are willing to accept per-platform differences in widget behaviour. Do not adopt it for a mobile-first product: the README states the Mobile/iOS port is in the works and considered incomplete. Before committing, verify what each backend actually renders for the controls you depend on, using the Eto.Test application in the repository, and check how the platform you target handles the widgets you cannot replace.

## FAQ

### What is Eto.Forms?

Eto.Forms is a cross-platform GUI framework for .NET that builds desktop applications on top of each platform's native toolkit, so one C# UI codebase produces a native-looking application on Windows, macOS and Linux. The README describes it as a framework for building applications that run across multiple platforms using their native toolkit with an easy to use API.

### Which platforms does Eto.Forms support?

The README states it currently supports desktop applications across Windows Forms, WPF, MonoMac and GTK#. A Mobile/iOS port exists but is described as incomplete.

### Where do I find Eto.Forms documentation and examples?

The README links to a Quick Start Guide and a Contributing Guide in the project wiki, and the repository contains a samples/ directory with WinForms, Wpf, MacOS and Gtk subdirectories plus a Tutorials folder. The README also points to Eto.Test, an application for testing the functionality of each widget.

## Sources

- [Issues](https://github.com/picoe/Eto/issues)
- [picoe/Eto on GitHub](https://github.com/picoe/Eto)
- [README](https://github.com/picoe/Eto/blob/develop/README.md)
- [Releases](https://github.com/picoe/Eto/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/picoe-eto
