Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

This article is a Private article. Only a writer and users who know the URL can access it.
Please change open range to public in publish setting if you want to share this article with other users.

WPF いつも脳死で App.xaml.cs に実装している内容

0
Posted at

はじめに

いつも脳死で App.xaml.cs に実装している内容の備忘録です。

改訂履歴

  • 2026/10/08 : 初版公開。

本文

1. 環境

  • .NET 8.0
  • Visual Studio Community 2022

2. 実装

事実上のエントリポイントとなる App.xaml.cs に Mutex を使用した二重起動検証と、未処理例外の捕捉処理を実装しています。

ハンドラ 説明
DispatcherUnhandledException WPF の Dispatcher 上で処理されずに残った例外を捕捉する。e.Handled = true を設定すると、アプリケーションの終了を回避して処理を継続できる(できないこともあるらしい)。
AppDomain.CurrentDomain.UnhandledException アプリケーションドメイン内で未処理となった例外を通知する。プロセス終了前のログ記録などに使用する。通常、このイベントで例外を処理しても、アプリケーションの終了は回避できないらしい。
TaskScheduler.UnobservedTaskException Task 内で発生した例外が観測されないまま、タスクがガベージコレクションの対象になった際などに発生する。e.SetObserved() で例外を観測済みとして扱える。
App.xaml.cs
using System.Reflection;
using System.Windows;
using System.Windows.Threading;

namespace WpfExample;

/// <summary>
/// Windows Presentation Foundation アプリケーションを表します。
/// </summary>
public partial class App : Application
{
    private static Mutex? s_mutex;
    private static string s_assemblyName = "Application";

    /// <summary>
    /// <see cref="Application.Startup"/> イベントを処理します。
    /// </summary>
    /// <param name="e">イベントデータを含む <see cref="StartupEventArgs"/>。</param>
    protected override void OnStartup(StartupEventArgs e)
    {
        try
        {
            base.OnStartup(e);

            s_assemblyName = Assembly
                .GetEntryAssembly()?
                .GetName()
                .Name ?? s_assemblyName;

            s_mutex = new Mutex(
                initiallyOwned: true,
                name: s_assemblyName,
                createdNew: out bool createdNew);

            if (!createdNew)
            {
                MessageBox.Show(
                    "The application is already running.",
                    s_assemblyName,
                    MessageBoxButton.OK,
                    MessageBoxImage.Information);

                Shutdown();
                return;
            }

            DispatcherUnhandledException +=
                OnDispatcherUnhandledException;

            AppDomain.CurrentDomain.UnhandledException +=
                OnUnhandledException;

            TaskScheduler.UnobservedTaskException +=
                OnUnobservedTaskException;
        }
        catch (Exception ex)
        {
            HandleException(ex);
            Shutdown();
        }
    }

    /// <summary>
    /// <see cref="Application.Exit"/> イベントを処理します。
    /// </summary>
    /// <param name="e">イベントデータを含む <see cref="ExitEventArgs"/>。</param>
    protected override void OnExit(ExitEventArgs e)
    {
        try
        {
            s_mutex?.ReleaseMutex();
        }
        catch
        {
            // 無視。
        }
        finally
        {
            s_mutex?.Dispose();
            s_mutex = null;
        }

        base.OnExit(e);
    }

    private void OnDispatcherUnhandledException(
        object sender,
        DispatcherUnhandledExceptionEventArgs e)
    {
        HandleException(e.Exception);

        // アプリを終了させない。
        e.Handled = true;
    }

    private void OnUnhandledException(
        object sender,
        UnhandledExceptionEventArgs e)
    {
        if (e.ExceptionObject is Exception ex)
        {
            HandleException(ex);
        }
    }

    private void OnUnobservedTaskException(
        object? sender,
        UnobservedTaskExceptionEventArgs e)
    {
        HandleException(e.Exception);

        // 例外処理したことをランタイムに通知する。
        e.SetObserved();
    }

    private static void HandleException(Exception exception)
    {
        try
        {
            // ログやメッセージの表示など、例外処理を実装する。
            MessageBox.Show(
                $"An unexpected error has occurred."
                    + Environment.NewLine
                    + exception,
                s_assemblyName,
                MessageBoxButton.OK,
                MessageBoxImage.Error);
        }
        catch
        {
            // 無視。
        }
    }
}

おわりに

本当に脳死で実装しています。DI コンテナやログも入れてもよかったかも。

0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?