次の方法で共有


C# マークアップ ホット リロード

基本的な使用

.NET MAUI アプリをアクティブにデバッグしている最中に .NET ホット リロードを使用するには、C# コードを変更した後、Visual Studio ツール バーの [コード変更の適用] ボタン (別名 🔥 ボタン) をクリックします。

C# Hot Reload Demo

警告

UI コードを変更すると、[コード変更の適用] ボタン (別名 🔥 ボタン) によって実行中の C# コードが直ちに更新されますが、UI の更新はすぐには行われない場合があります (「高度な使用方法」を参照してください)。 この原因は、.NET MAUI が、ユーザーによって行われたばかりの実行中の中間言語に対する根底での変更を認識していないためです。

ただし、実行中のコードは実際に更新されているので、更新された UI を画面に再描画するように .NET MAUI に指示するだけで済みます

簡単な解決策は、.NET ホット リロードの変更が適用された現在のページから移動した後、そのページに戻ることで、.NET MAUI にその UI を更新するように強制することです。 これにより、.NET MAUI は画面に UI を再描画することを強制されます。

更新された UI を再描画するように .NET MAUI に自動的に指示する方法の詳細については、「高度な使用方法」を参照してください。

高度な使用方法

.NET エコシステムにおいて .NET MAUI と .NET ホット リロードの間にはギャップが存在し、.NET MAUI アプリ UI は、[コード変更の適用] ボタン (別名 🔥 ボタン) を押しても自動的に更新されません。 アプリの根底の中間言語でコードが更新されても、更新された UI を画面に再描画するよう .NET MAUI に指示するものは存在しません。

ただし、ICommunityToolkitHotReloadHandler を実装してそれを .NET MAUI の依存関係注入コンテナーに登録することで、UI を再描画するように .NET MAUI に手動で指示できます (以下に例を示します)。

MetadataUpdateHandler

.NET ホット リロードは実行される際に、System.Reflection.Metadata.MetadataUpdateHandler 経由で Type[] を提供することで更新された各 Type を決定します。

.NET MAUI C# Markup Community Toolkit は、ICommunityToolkitHotReloadHandler.OnHotReload(IReadOnlyList<Type> types) 経由で変更された型を決定します。

以下のように .NET MAUI の依存関係注入コンテナーに ICommunityToolkitHotReloadHandler の実装を登録することで、[コード変更の適用] ボタン (別名 🔥 ボタン) が押されるたびに OnHotReload メソッドが自動的に起動します。

builder.Services.AddSingleton<ICommunityToolkitHotReloadHandler, HotReloadHandler>();

ICommunityToolkitHotReloadHandler の実装例

この例は、[コード変更の適用] ボタン (別名 🔥 ボタン) が押されたときにアプリ UI を自動的に再描画するように .NET MAUI に指示するための ICommunityToolkitHotReloadHandler を実装する方法を示しています。

Note

これは、すべてのアプリで動作する包括的な例ではありません。 この例はほとんどのアプリで機能しますが、それぞれの .NET MAUI アプリはアーキテクチャと実装が異なるため、各自のコード ベースで最適に機能するようにコード例を変更することをお勧めします。

MauiProgram.cs

以下のように MauiProgram.cs で、ICommunityToolkitHotReloadHandler の実装を .NET MAUI の依存関係注入コンテナーに追加します。

public class MauiProgram
{
	public static MauiApp CreateMauiApp()
	{
		// ...
        // Additional code ommitted for brevity
        // ...

		// Register C# Hot Reload Handler
		builder.Services.AddSingleton<ICommunityToolkitHotReloadHandler, HotReloadHandler>();

		// ...
        // Additional code ommitted for brevity
        // ...
	}
}

HotReloadHandler.cs

ICommunityToolkitHotReloadHandler の実装では、画面に UI を再描画するように .NET MAUI に指示します。

以下の例は、シェル アーキテクチャと非シェル アーキテクチャの両方を処理し、モーダルで表示されるページのサポートを含んでいます。

Note

これは、すべてのアプリで動作する包括的な例ではありません。 この例はほとんどのアプリで機能しますが、それぞれの .NET MAUI アプリはアーキテクチャと実装が異なるため、各自のコード ベースで最適に機能するようにコード例を変更することをお勧めします。

using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;

namespace CommunityToolkit.Maui.Markup.Sample;

class HotReloadHandler : ICommunityToolkitHotReloadHandler
{
	public async void OnHotReload(IReadOnlyList<Type> types)
	{
		if (Application.Current?.Windows is null)
		{
			Trace.WriteLine($"{nameof(HotReloadHandler)} Failed: {nameof(Application)}.{nameof(Application.Current)}.{nameof(Application.Current.Windows)} is null");
			return;
		}

		foreach (var window in Application.Current.Windows)
		{
			if (window.Page is not Page currentPage)
			{
				return;
			}

			foreach (var type in types)
			{
				if (type.IsSubclassOf(typeof(Page)))
				{
					if (window.Page is AppShell shell)
					{
						if (shell.CurrentPage is Page visiblePage
							&& visiblePage.GetType() == type)
						{
							var currentPageShellRoute = AppShell.GetRoute(type);

							await currentPage.Dispatcher.DispatchAsync(async () =>
							{
								await shell.GoToAsync(currentPageShellRoute, false);
								shell.Navigation.RemovePage(visiblePage);
							});

							break;
						}
					}
					else
					{
						if (TryGetModalStackPage(window, out var modalPage))
						{
							await currentPage.Dispatcher.DispatchAsync(async () =>
							{
								await currentPage.Navigation.PopModalAsync(false);
								await currentPage.Navigation.PushModalAsync(modalPage, false);
							});
						}
						else
						{
							await currentPage.Dispatcher.DispatchAsync(async () =>
							{
								await currentPage.Navigation.PopAsync(false);
								await currentPage.Navigation.PushAsync(modalPage, false);
							});
						}

						break;
					}
				}
			}
		}
	}


	static bool TryGetModalStackPage(Window window, [NotNullWhen(true)] out Page? page)
	{
		page = window.Navigation.ModalStack.LastOrDefault();
		return page is not null;
	}
}