Marcação/Recarga Dinâmica do C#

Uso básico

Para usar a Recarga Dinâmica do .NET ao depurar ativamente seu aplicativo .NET MAUI, modifique seu código C# e clique no botão Aplicar alterações de código (também conhecido como botão 🔥) na barra de ferramentas do Visual Studio.

C# Hot Reload Demo

Aviso

Ao modificar o código da interface do usuário, o botão Aplicar alterações de código (também conhecido como botão 🔥) atualizará o código C# em execução imediatamente, mas pode não atualizar sua interface do usuário imediatamente (consulte Uso Avançado). Isso ocorre por que o .NET MAUI não está ciente das alterações subjacentes que você acabou de fazer na linguagem intermediária em execução.

A boa notícia é que o código em execução realmente foi atualizado e basta informar ao .NET MAUI para redesenhar a interface do usuário atualizada na tela

Uma solução fácil é forçar o .NET MAUI a atualizar sua interface do usuário saindo da página atual em que a Recarga Dinâmica do .NET foi aplicada e, em seguida, voltando para essa página. Isso força o .NET MAUI a redesenhar a interface do usuário na tela.

Consulte Uso Avançado para obter mais informações sobre como informar automaticamente ao .NET MAUI para redesenhar a interface do usuário atualizada.

Uso Avançado

Existe uma lacuna no ecossistema do .NET entre o .NET MAUI e a Recarga Dinâmica do .NET: a interface do usuário do aplicativo .NET MAUI não é atualizada automaticamente depois de pressionar o botão Aplicar alterações de código (também conhecido como botão 🔥). Embora seu código tenha sido atualizado na linguagem intermediária, nada informou ao .NET MAUI para redesenhar a interface do usuário atualizada na tela.

A boa notícia é que podemos informar manualmente ao .NET MAUI para redesenhar a interface do usuário implementando ICommunityToolkitHotReloadHandler e registrando-a no contêiner de injeção de dependência do .NET MAUI (exemplo abaixo).

MetadataUpdateHandler

Quando a Recarga Dinâmica do .NET é executada, ela apresenta cada Type atualizada fornecendo Type[] por meio de System.Reflection.Metadata.MetadataUpdateHandler.

O .NET MAUI Community Toolkit de Marcação C# apresenta os tipos alterados por meio de ICommunityToolkitHotReloadHandler.OnHotReload(IReadOnlyList<Type> types).

Registrar a implementação de ICommunityToolkitHotReloadHandler com o contêiner de injeção de dependência do .NET MAUI garante que o método OnHotReload será acionado automaticamente sempre que o botão Aplicar alterações de código (também conhecido como botão 🔥) for pressionado:

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

Implementação de exemplo de ICommunityToolkitHotReloadHandler

Este exemplo demonstra como implementar ICommunityToolkitHotReloadHandler para informar ao .NET MAUI para redesenhar automaticamente a interface do usuário do aplicativo quando o botão Aplicar alterações de código (também conhecido como botão 🔥) for pressionado.

Observação

Este não é um exemplo abrangente que funcionará para cada aplicativo. Este exemplo funcionará para a maioria dos aplicativos, mas como cada aplicativo .NET MAUI é projetado + implementado de forma diferente, é recomendável modificar o código de exemplo para funcionar melhor para sua base de código.

MauiProgram.cs

Em MauiProgram.cs, adicione a implementação de ICommunityToolkitHotReloadHandler ao contêiner de injeção de dependência do .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

Na implementação de ICommunityToolkitHotReloadHandler, informamos ao .NET MAUI para redesenhar a interface do usuário na tela.

O exemplo abaixo trata as arquiteturas Shell e não Shell e inclui suporte para páginas exibidas de forma modal.

Observação

Este não é um exemplo abrangente que funcionará para cada aplicativo. Este exemplo funcionará para a maioria dos aplicativos, mas como cada aplicativo .NET MAUI é projetado + implementado de forma diferente, é recomendável modificar o código de exemplo para funcionar melhor para sua base de código.

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;
	}
}