Search code examples
xamarincross-platformsystem-tray

Building a Tray Application using Xamarin?


Using .NET Core and Xamarin I thought about building an application that would run on both Windows and macOS environments.

The .NET Core part would be used for all backend stuff and provide its functionality as a REST API. .NET Core however, does not have any support for building native UI applications (WPF, ...) so that's a no-go for building a tray application.

So I thought about using Xamarin for this. But I can't seem to figure out if this is at all possible. Nor can I find any leads on how to get started.

Some alternatives I've not yet further investigated:

  • Mono, but that doesn't have any integration with VS2017 so that's out...
  • QT, but that's aimed at C++, so that's out as well
  • Java, but then why bother using .NET Core in the first place...
  • Electron.js

Solution

  • For Windows, Xamarin.Forms will not officially support WPF till 3.0.

    re: https://blog.xamarin.com/glimpse-future-xamarin-forms-3-0/

    In terms of a Tray app, that is native Windows code and would not be a part of Xamarin.Forms UI code, but the native Windows code that would show/hide your app's UI (assumably Xamarin.Forms based)

    For macOS, Xamarin.Forms is supported via Xamarin.Mac, and is currently in a "preview" release.

    As far as the equivalent of a tool tray app on macOS, in Xamarin.Mac you can create a item (icon and/or text based) in the system status bar.

    Typically this is done in the NSApplicationDelegate.DidFinishLaunching and is easy as:

    statusItem = NSStatusBar.SystemStatusBar.CreateStatusItem(NSStatusItemLength.Variable);
    statusItem.Button.Image = new NSImage("moviemadness_icon_dark.png")
    {
        Template = true
    };
    statusItem.Button.Action = new Selector("StatusItemButtonAction:");
    

    In this example, any time the icon/text in the status is tapped, the StatusItemButtonAction method is triggered and it either terminates itself if you were holding the control key down at the same time, otherwise it runs the StatusBarPopOver which in my case constructs a NSPopover and shows an embedded Xamarin.Forms TabbedPage UI that shows the mobile app server status, current users of the app, the app analytics, etc...

    [Action("StatusItemButtonAction:")]
    public void StatusItemButtonAction(NSStatusBarButton sender)
    {                                     
        var currentEvent = NSApplication.SharedApplication.CurrentEvent;
        if (currentEvent.ModifierFlags.HasFlag(NSEventModifierMask.AlternateKeyMask) || 
            currentEvent.ModifierFlags.HasFlag(NSEventModifierMask.ControlKeyMask))
            NSApplication.SharedApplication.Terminate(this);
        else
            StatusBarPopOver();
    }