DEV Community

Masui Masanori
Masui Masanori

Posted on

3 3 1 1 1

[C#][Uno Platform] Create desktop applications on Ubuntu 2

Intro

This time, I will try installing NuGet packages, using DI, firing life-cycle events.

Environments

  • Ubuntu ver.21.10
  • .NET ver.6.0.101
  • Uno Platform ver.4.0.11

Installing NuGet packages

To log, using DI, etc., I want to install NuGet packages.
When I install packages by NuGet Package Manager, I have to select the target project.

To use the packages in all projects, I have to install into "UnoSolutionTemplate.net6.csproj".

If the package is only for specific platform, I have to add in specific projects.

Life-cycle events

Sometimes, I want to execute something on loading the page, closing the page, and so on.

Shared project

In "UnoSample.Shared", I can use "Loaded" event in MainPage.xaml.cs to execute on the page loaded.

MainPage.xaml.cs

using Windows.UI.Xaml.Controls;
using UnoSample.ViewModels;

namespace UnoSample
{
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.Loaded += (sender, e) => Console.WriteLine("Loaddeded");
            this.InitializeComponent();
            this.DataContext = new MainPageViewModel();
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

How about closing applications event?
I can't find any events what are called on closing.

So I think I shall use closing events in every specific platform projects.
For example, WPF can use "OnClosing" and "OnClosed" methods.

Executing on closing

When I open MainPage, these classes are instantiated in sequence.

Image description

In "UnoSample.Skia.Gtk" project, there is only "Main" method.
So I can execute closing operations after "host.Run()".

Program.cs

using GLib;
using Uno.UI.Runtime.Skia;
using UnoSample.Skia.Gtk.MotionControllers;

namespace UnoSample.Skia.Gtk
{
    class Program
    {
        static void Main(string[] args)
        {
            // I also can use "using statement"
            using(var motionController = new MotionController())
            {
                ExceptionManager.UnhandledException += delegate (UnhandledExceptionArgs expArgs)
                {
                    expArgs.ExitApplication = true;
                };
                var host = new GtkHost(() => new App(), args);
                host.Run();
                // execute closing operations.
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Call methods in UnoSample.Shared classes

How shall I call methods in UnoSample.Shared classes?

I can access App.xaml.cs like below.

App.xaml.cs

...
namespace UnoSample
{
    public sealed partial class App : Application
    {
        private Window _window;
        public void Greet(string message)
        {
            Console.WriteLine($"SharedApp {message}");
        }
...
Enter fullscreen mode Exit fullscreen mode

Program.cs

...
    class Program
    {
        static void Main(string[] args)
        {
            using(var motionController = new MotionController())
            {
...
                var host = new GtkHost(() => new App(), args);
                host.Run();
                // Because I can't get instances by "App.Current" before executing "host.Run()",
                // I can only execute closing operations from Program.cs. 
                ((App)App.Current).Greet("Call from Gtk");
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

DI (Dependency Injection)

Because I want to avoid the classes are coupled tightly, I try using DI framework.
In this time, I tried using "Microsoft.Extensions.DependencyInjection(ver.6.0.0)"

Because I couldn't find the way to inject View and their code behinds, I put IServiceProvider into App.xaml.cs of the shared project and get injected instances from it.

Program.cs

using GLib;
using Microsoft.Extensions.DependencyInjection;
using Uno.UI.Runtime.Skia;
using UnoSample.ViewModels;

namespace UnoSample.Skia.Gtk
{
    class Program
    {
        static void Main(string[] args)
        {
            var servicesProvider = BuildDi(args);
            using (servicesProvider as IDisposable)
            {
...
                var host = new GtkHost(() => new App(servicesProvider), args);
                host.Run();
            }
        }
        private static IServiceProvider BuildDi(string[] args)
        {
            var services = new ServiceCollection();
            services.AddScoped<MainPageViewModel>();
            return services.BuildServiceProvider();
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

App.xaml.cs

...
namespace UnoSample
{
    public sealed partial class App : Application
    {
        private Window? _window;
        public IServiceProvider ServiceProvider { get; }

        public App(IServiceProvider serviceProvider)
        {
            this.ServiceProvider = serviceProvider;
            InitializeLogging();

            this.InitializeComponent();
...
Enter fullscreen mode Exit fullscreen mode

MainPage.xaml.cs

using Windows.UI.Xaml.Controls;
using UnoSample.ViewModels;

namespace UnoSample
{
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
            this.DataContext = ((App)App.Current).ServiceProvider.GetService(typeof(MainPageViewModel));
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

I'm not sure if this is the best method.
Maybe it's better to use another DI framework。

If I will find more better one, I will edit this post or write new post.

Sentry image

Hands-on debugging session: instrument, monitor, and fix

Join Lazar for a hands-on session where you’ll build it, break it, debug it, and fix it. You’ll set up Sentry, track errors, use Session Replay and Tracing, and leverage some good ol’ AI to find and fix issues fast.

RSVP here →

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay