使用 MetadataUpdateHandler 扩展 .NET 热重载(C#、Visual Basic)

可以通过编程方式扩展 .NET 热重载支持,以实现对通常不支持的其他场景的支持,例如代码更改后需要清除缓存或刷新 UI。 例如,若要支持 JSON 序列化程序的热重载,需要在修改类型时清除其缓存。 对于 .NET MAUI 开发人员,可能需要为在正常条件下不触发热重载(例如编辑构造函数或 UI 元素的事件处理程序)的编辑/更新扩展热重载。 可以使用 MetadataUpdateHandlerAttribute 刷新应用程序状态、触发 UI 重新呈现或执行类似的操作。

此属性指定的类型应实现与以下一个或多个签名匹配的静态方法:

static void ClearCache(Type[]? updatedTypes)
static void UpdateApplication(Type[]? updatedTypes)

ClearCache 使更新处理程序有机会清除基于应用程序的元数据推断的任何缓存。 在调用所有 ClearCache 方法之后,UpdateApplication 会被调用,针对每个指定方法的处理程序。 你可能会使用 UpdateApplication 来刷新 UI。

Example

以下示例演示了最初不支持热重载的 .NET MAUI 项目的场景,但在实现 MetadataUpdateHandler后支持该功能。

测试 .NET 热重载

  1. 在 Visual Studio 中创建新的 .NET MAUI 项目。 选择 .NET MAUI 应用 项目模板。

  2. App.xaml.cs中,将代码替换为以下代码来创建 MainPage:

    //MainPage = new MainPage(); // Template default code
    MainPage = new NavigationPage(new MainPage());
    

    接下来,实现生成方法以简化 C# 中的 UI 更新。 此方法设置ContentPage.Content并在页面的OnNavigatedTo中调用。 事件 OnNavigatedTo 必须托管在 Shell 或 NavigationPage 中。

  3. MainPage.xaml.cs中,将 MainPage 构造函数代码替换为以下代码:

    public MainPage()
    {
       InitializeComponent();
       Build();
    }
    
    void Build() => Content =
       new Label
       {
          Text = "First line\nSecond line"
       };
    
    protected override void OnNavigatedTo(NavigatedToEventArgs args)
    {
       base.OnNavigatedTo(args);
       Build();
    }
    
  4. F5 启动应用。

  5. 加载页面后,将 C# 代码中的标签文本更改为“第一行\n第二行\n第三行”

  6. 选择 “热重载”按钮。这是“热重载”按钮的屏幕截图。

    更新后的文本不会显示在正在运行的应用中。 默认情况下,此方案没有热重载支持。

    热重载不起作用的屏幕截图。

添加 MetadataUpdateHandler

在 .NET MAUI 应用中,在进行代码更改后,必须执行一些作来重新运行 C# UI 代码。 如果 UI 代码是用 C# 编写的,那么可以在 MetadataUpdateHandler 中使用 UpdateApplication 方法来重新加载 UI。 若要设置此设置,请使用以下代码 将HotReloadService.cs 添加到应用程序。

#if DEBUG
[assembly: System.Reflection.Metadata.MetadataUpdateHandlerAttribute(typeof(YourAppNamespace.HotReloadService))]
namespace YourAppNamespace { 
    public static class HotReloadService
    {
        #pragma warning disable CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
        public static event Action<Type[]?>? UpdateApplicationEvent;
        #pragma warning restore CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

        internal static void ClearCache(Type[]? types) { }
        internal static void UpdateApplication(Type[]? types) {
            UpdateApplicationEvent?.Invoke(types);
        }
    }
}
#endif

确保将 YourAppNamespace 替换为您要定位的页面的命名空间。

现在,添加上述代码后,在 Visual Studio 中编辑实时代码时,会发生元数据更改,应用会调度该 UpdateApplicationEvent代码。 因此,需要添加代码来注册事件并执行 UI 更新。

注释

对于此方案,必须启用 XAML 热重载。

MainPage.xaml.cs中,添加代码以在OnNavigatedTo事件中注册UpdateApplicationEvent事件处理程序。

protected override void OnNavigatedTo(NavigatedToEventArgs args)
    {
        base.OnNavigatedTo(args);

        Build();

#if DEBUG
        HotReloadService.UpdateApplicationEvent += ReloadUI;
#endif
    }

取消订阅OnNavigatedFrom中的事件处理程序后,添加代码处理事件并重新执行对Build的调用。

protected override void OnNavigatedFrom(NavigatedFromEventArgs args)
   {
   base.OnNavigatedFrom(args);

#if DEBUG
   HotReloadService.UpdateApplicationEvent -= ReloadUI;
#endif
    }

private void ReloadUI(Type[] obj)
{
   MainThread.BeginInvokeOnMainThread(() =>
   {
      Build();
   });
}

现在,启动应用。 更改 C# 代码中的标签文本并按下“Hot Reload”按钮时,UI 就会刷新!

热重载工作的屏幕截图。