<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>handling Archive - Robert Skibbe</title>
	<atom:link href="https://robbelroot.de/blog/tag/handling/feed/" rel="self" type="application/rss+xml" />
	<link></link>
	<description>alias RobbelRoot – Freelance Full Stack Developer .NET</description>
	<lastBuildDate>Sun, 10 Sep 2023 23:39:10 +0000</lastBuildDate>
	<language>de</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://robbelroot.de/wp-content/uploads/2020/12/cropped-favicon-32x32.png</url>
	<title>handling Archive - Robert Skibbe</title>
	<link></link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Handling the application exit in Avalonia UI based .NET apps</title>
		<link>https://robbelroot.de/blog/handling-the-application-exit-in-avaloniaui-based-net-apps/</link>
					<comments>https://robbelroot.de/blog/handling-the-application-exit-in-avaloniaui-based-net-apps/#respond</comments>
		
		<dc:creator><![CDATA[Robert Skibbe]]></dc:creator>
		<pubDate>Sun, 10 Sep 2023 23:15:54 +0000</pubDate>
				<category><![CDATA[Avalonia UI]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[application]]></category>
		<category><![CDATA[applicationexit]]></category>
		<category><![CDATA[avalonia]]></category>
		<category><![CDATA[avalonia ui]]></category>
		<category><![CDATA[close]]></category>
		<category><![CDATA[closing]]></category>
		<category><![CDATA[csharp]]></category>
		<category><![CDATA[dotnet]]></category>
		<category><![CDATA[event]]></category>
		<category><![CDATA[events]]></category>
		<category><![CDATA[exit]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[handle]]></category>
		<category><![CDATA[handling]]></category>
		<category><![CDATA[interface]]></category>
		<category><![CDATA[library]]></category>
		<category><![CDATA[lifetime]]></category>
		<category><![CDATA[ui]]></category>
		<category><![CDATA[user interface]]></category>
		<guid isPermaLink="false">https://robbelroot.de/?p=16003</guid>

					<description><![CDATA[<p>So you are developing an Avalonia UI 11 app and asking yourself: &#8222;How can I actually react to app exits?&#8220;. This could be fore example useful, if you want to like save the user configuration on exit. On today&#8217;s post I will show you a pretty easy example on how &#8230;</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/handling-the-application-exit-in-avaloniaui-based-net-apps/">Handling the application exit in Avalonia UI based .NET apps</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/09/Avalonia-UI-handling-application-exit-closing-or-shutdown-events.png"><img fetchpriority="high" decoding="async" width="640" height="360" src="https://robbelroot.de/wp-content/uploads/2023/09/Avalonia-UI-handling-application-exit-closing-or-shutdown-events.png" alt="Avalonia UI handling application exit closing or shutdown events" class="wp-image-16017" title="Avalonia UI handling application exit closing or shutdown events"/></a><figcaption class="wp-element-caption">Avalonia UI handling application exit closing or shutdown events</figcaption></figure>






<p>So you are developing an Avalonia UI 11 app and asking yourself: &#8222;How can I actually react to app exits?&#8220;. This could be fore example useful, if you want to like save the user configuration on exit. On today&#8217;s post I will show you a pretty easy example on how to create or react to some sort of global &#8222;Exit Event&#8220;.</p>



<p class="info-banner">&#x1f4a1; In a hurry? I got you covered! To solve this issue (in my case), I just added a handler to the &#8222;ShutdownRequested&#8220; event residing in &#8222;IClassicDesktopStyleApplicationLifetime&#8220; based object instances.  Then I wrote my custom handler which fires a more globally available event. Take a look at <strong><a href="#the-solution">the solution located at the bottom</a></strong> of this post, to get more information.</p>



<style>
.info-banner {
    background: #03a9f4;
    padding: 2em;
    border-radius: 0.5em;
    color: whitesmoke;
}
.info-banner a {
    color: #FED766;
}
</style>



<h2 class="wp-block-heading">Handling application closing events &#8211; a common task</h2>



<p>Today I just stumbled upon the task of &#8222;How to handle the shutdown event of an Avalonia UI app?&#8220; myself. I needed to <strong><a href="https://robbelroot.de/blog/rskibbe-ini-parsing-reading-saving-ini-files-but-easy/" target="_blank" rel="noreferrer noopener">save an Ini-File</a></strong> when the program was closing, to make sure, that the user configuration is persisted, before the application fully closes. I thought, well, I could just use the normal way – but then I remembered, that I&#8217;m using the Avalonia UI side of things, not like typical WPF or Windows Forms.</p>



<p>When googling myself I didn&#8217;t find pretty much what I wanted, because there was some split up information. Some things found in the Avalonia UI documentation, some things on usual places like stackoverflow, etc. With this post I&#8217;m sort of writing a reminder for myself and wanted to share it with the developer world as well, if you are having the same problem.</p>



<h2 class="wp-block-heading">First &#8211; but failed &#8211; attempts for handling application exits</h2>



<p>When thinking about like the typical old Windows Forms (Winforms) applications, you could just subscribe and handle the <a href="https://learn.microsoft.com/de-de/dotnet/api/system.windows.forms.application.applicationexit?view=windowsdesktop-7.0" target="_blank" rel="noreferrer noopener"><strong>&#8222;Application.ApplicationExit&#8220;-Event</strong></a>. For sure, you could do things like handling single Form Closing events and if the corresponding form was the last one &#8211; well, then mostly the application exits as well. Trying this with Avalonia won&#8217;t work – as you might already found out for yourself.</p>



<h3 class="wp-block-heading">No Windows Forms like Application.ApplicationExit?</h3>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/09/Trying-to-handle-Avalonia-UI-application-exit-with-typical-WPF-Application.Exit-event.png"><img decoding="async" width="474" height="207" src="https://robbelroot.de/wp-content/uploads/2023/09/Trying-to-handle-Avalonia-UI-application-exit-with-typical-WPF-Application.Exit-event.png" alt="Trying to handle Avalonia UI application exit with typical WPF Application.Exit event" class="wp-image-16028" title="Trying to handle Avalonia UI application exit with typical WPF Application.Exit event"/></a><figcaption class="wp-element-caption">Trying to handle Avalonia UI application exit with typical Winforms Application.ApplicationExit event</figcaption></figure>



<h3 class="wp-block-heading">But how about WPF&#8217;s Application.Exit?</h3>



<p>Trying it the WPF style wouldn&#8217;t work too, as you <strong><a href="https://learn.microsoft.com/de-de/dotnet/api/system.windows.application.exit?view=windowsdesktop-7.0" target="_blank" rel="noreferrer noopener">don&#8217;t have the &#8222;Application.Exit&#8220; event</a></strong> either. No such available event is listed when entering the letters as sub-thing for the Application class.</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/09/Trying-to-handle-Avalonia-UI-application-exit-with-typical-Winforms-Application.ApplicationExit-event.png"><img decoding="async" width="511" height="215" src="https://robbelroot.de/wp-content/uploads/2023/09/Trying-to-handle-Avalonia-UI-application-exit-with-typical-Winforms-Application.ApplicationExit-event.png" alt="Trying to handle Avalonia UI application exit with typical Winforms Application.ApplicationExit event" class="wp-image-16022" title="Trying to handle Avalonia UI application exit with typical Winforms Application.ApplicationExit event"/></a><figcaption class="wp-element-caption">Trying to handle Avalonia UI application exit with typical WPF Application.Exit event</figcaption></figure>



<p>So there has to be another possibility to catch something like a global &#8222;Avalonia UI app exit event&#8220;. Let&#8217;s take a look at this in the next section. As always &#8211; feel free to comment if you have a better alternative solution.</p>



<h2 class="wp-block-heading" id="the-solution">A possible solution</h2>



<p>In the end I came to the following solution for my own infrastructure / program setup. Maybe there&#8217;s another, maybe there&#8217;s a better one &#8211; feel free to comment, if you found another one. In the end, you have to decide yourself what&#8217;s a &#8222;best fit&#8220; for your rules (like developing with the MVVM pattern, etc.).</p>



<h3 class="wp-block-heading">Going into App.axaml</h3>



<p>With Avalona UI you will have an App.axaml file. Just click it for example inside the solution folder of Visual Studio and navigate to the code behind by pressing F7 &#8211; or use any other known method for that. Being inside that raw file, it should like the following for a desktop driven app. Keep in mind, that I&#8217;m using a specific syntax for the if statement here. I&#8217;m also using a DI driven &#8222;get me a MainWindowViewModel&#8220; approach &#8211; but that&#8217;s not the key here anyways&#8230;</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// some imports
// namespace etc

public partial class App : Application
{

    public override void Initialize()
    {
        AvaloniaXamlLoader.Load(this);
    }

    public override void OnFrameworkInitializationCompleted()
    {

        if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
        {
            desktop.MainWindow = new MainWindow()
            {
                DataContext = Locator.Current.GetService&lt;MainWindowViewModel>(),
            };
        }

        base.OnFrameworkInitializationCompleted();
    }

}</pre>



<h3 class="wp-block-heading">Checking on Avalonia UI ApplicationLifetime&#8217;s</h3>



<p>If you take a closer look (or search) at the documentation for Avalonia UI, you will find something called &#8222;ApplicationLifetime&#8220;. Please <strong><a href="https://docs.avaloniaui.net/docs/next/concepts/application-lifetimes" target="_blank" rel="noreferrer noopener">refer to the corresponding article / section</a></strong> to get more detailed information on that, I will focus more on our problem here. You will basically find code like the one I&#8217;ve posted above there. But the most important part is that overriden &#8222;OnFrameworkInitializationCompleted&#8220; method.</p>



<p>We can check the &#8222;ApplicationLifetime&#8220; Property of the &#8222;Avalonia.Application&#8220; class and work further on that. In the code above (and in the example code from the documentation) we tried to check, if the current &#8222;ApplicationLifetime&#8220; is a &#8222;IClassicDesktopStyleApplicationLifetime&#8220;. If so, we have it assigned to a variable called desktop – and this is where things get interesting.</p>



<h3 class="wp-block-heading">One publisher, multiple subscribers</h3>



<p><strong>The &#8222;desktop&#8220; variable implementing the mentioned interface provides an event called &#8222;ShutdownRequested&#8220; – tada, exactly what we wanted, right!?</strong> Usually you would now try to access this stuff from different places in the form of:</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/09/Avalonia-UI-App-publishing-a-Shutdown-event-for-the-ViewModels-to-subscribe-to.png"><img loading="lazy" decoding="async" width="808" height="436" src="https://robbelroot.de/wp-content/uploads/2023/09/Avalonia-UI-App-publishing-a-Shutdown-event-for-the-ViewModels-to-subscribe-to.png" alt="Avalonia UI App publishing a Shutdown event for the ViewModels to subscribe to" class="wp-image-16045" title="Avalonia UI App publishing a Shutdown event for the ViewModels to subscribe to"/></a><figcaption class="wp-element-caption">Avalonia UI App publishing a Shutdown event for the ViewModels to subscribe to</figcaption></figure>



<p>But that doesn&#8217;t really work, at least with the search and tries I did. I couldn&#8217;t figure out how to retrieve the current app lifetime for example in a ViewModel to say &#8222;Hey, if the app get&#8217;s closed, do this or that&#8220;. So in the end, I made it work like this, but manually. Append your custom evenhandler to the &#8222;ShutdownRequested&#8220; event of the casted &#8222;ApplicationLifetime&#8220;:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// the other code inside the override "OnFrameworkInitializionCompleted"
// method of the App class

desktop.ShutdownRequested += This_ShutdownRequested;

// other code

// as a separate method, define the handler
// optionally with some sort of debug output for testing, or use step debugging...
    protected virtual void This_ShutdownRequested(object? sender, ShutdownRequestedEventArgs e)
    {
        Debug.WriteLine($"App.{nameof(This_ShutdownRequested)}");
        OnShutdownRequested(e);
    }

// in conjunction with typical .NET events, we will create the used "OnXy" method
    protected virtual void OnShutdownRequested(ShutdownRequestedEventArgs e)
    {
        ShutdownRequested?.Invoke(this, e);
    }

// and define the event
public event EventHandler&lt;ShutdownRequestedEventArgs>? ShutdownRequested;</pre>



<h3 class="wp-block-heading">Subscribing to the Shutdown event globally</h3>



<p>If you are inside for example a ViewModel, you can now access and subscribe the defined event. Just grab the current &#8222;App&#8220; class instance by accessing the &#8222;Current&#8220; property of the &#8222;Application&#8220; class. Then make a null check and subscribe the usual C# event handling way. You could do this for example inside a constructor of a viewmodel and unsubscribe on deactivation.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// somwhere executable like in a ViewModel constructor
App app = Application.Current as App;
if (app != null)
    app.ShutdownRequested += This_ShutdownRequested;

// declaring the handler method
    private void This_ShutdownRequested(object? sender, ShutdownRequestedEventArgs e)
    {
        Debug.WriteLine("App shutting down");
    }</pre>



<h3 class="wp-block-heading">Cancelling the close mechanism</h3>



<p>If you want to cancel the closing of the application, you can do it like the usual way. The &#8222;ShutdownRequestedEventArgs&#8220; parameter &#8222;e&#8220; has a typical &#8222;e.Cancel&#8220; property. Just set it to true inside the handler and the app exit will be cancelled.</p>



<h2 class="wp-block-heading">Full code for App.axaml.cs</h2>



<p>Here you can find the complete code letting your &#8222;App&#8220; class provide a more centralized &#8222;Shutdown&#8220;, &#8222;Exit&#8220; or &#8222;Closing&#8220; event (based on your naming) in your Avalonia UI app. <strong>Keep in mind that you will need to adjust most of the namespaces and that only the class / the handling of the event is mandatory for you:</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using rskibbe.Motraso.GUI.ViewModels;
using rskibbe.Motraso.GUI.Views;
using Splat;
using System;
using System.Diagnostics;

namespace rskibbe.Motraso.GUI;

public partial class App : Application
{

    public override void Initialize()
    {
        AvaloniaXamlLoader.Load(this);
    }

    public override void OnFrameworkInitializationCompleted()
    {

        if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
        {

            desktop.ShutdownRequested += This_ShutdownRequested;
            desktop.MainWindow = new MainWindow()
            {
                DataContext = Locator.Current.GetService&lt;MainWindowViewModel>(),
            };
        }

        base.OnFrameworkInitializationCompleted();
    }

    protected virtual void This_ShutdownRequested(object? sender, ShutdownRequestedEventArgs e)
    {
        Debug.WriteLine($"App.{nameof(This_ShutdownRequested)}");
        OnShutdownRequested(e);
    }

    protected virtual void OnShutdownRequested(ShutdownRequestedEventArgs e)
    {
        ShutdownRequested?.Invoke(this, e);
    }

    public event EventHandler&lt;ShutdownRequestedEventArgs>? ShutdownRequested;

}</pre>
<p>Der Beitrag <a href="https://robbelroot.de/blog/handling-the-application-exit-in-avaloniaui-based-net-apps/">Handling the application exit in Avalonia UI based .NET apps</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://robbelroot.de/blog/handling-the-application-exit-in-avaloniaui-based-net-apps/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
