diff --git a/src/SourceGenerators/Uno.UI.SourceGenerators/Content/Uno.UI.SourceGenerators.props b/src/SourceGenerators/Uno.UI.SourceGenerators/Content/Uno.UI.SourceGenerators.props
index 4d9faac51364..ec3c980b8954 100644
--- a/src/SourceGenerators/Uno.UI.SourceGenerators/Content/Uno.UI.SourceGenerators.props
+++ b/src/SourceGenerators/Uno.UI.SourceGenerators/Content/Uno.UI.SourceGenerators.props
@@ -68,6 +68,8 @@
+
+
diff --git a/src/Uno.UI.RemoteControl/HotReload/ClientHotReloadProcessor.Agent.cs b/src/Uno.UI.RemoteControl/HotReload/ClientHotReloadProcessor.Agent.cs
index cca3153bba72..4f8ec059ac03 100644
--- a/src/Uno.UI.RemoteControl/HotReload/ClientHotReloadProcessor.Agent.cs
+++ b/src/Uno.UI.RemoteControl/HotReload/ClientHotReloadProcessor.Agent.cs
@@ -22,7 +22,8 @@ namespace Uno.UI.RemoteControl.HotReload
partial class ClientHotReloadProcessor
{
private bool _linkerEnabled;
- private HotReloadAgent _agent;
+ private HotReloadAgent? _agent;
+ private bool _metadataUpdatesEnabled;
private static ClientHotReloadProcessor? _instance;
private readonly TaskCompletionSource _hotReloadWorkloadSpaceLoaded = new();
@@ -41,6 +42,8 @@ partial void InitializeMetadataUpdater()
{
_instance = this;
+ _metadataUpdatesEnabled = BuildMetadataUpdatesEnabled();
+
_linkerEnabled = string.Equals(Environment.GetEnvironmentVariable("UNO_BOOTSTRAP_LINKER_ENABLED"), "true", StringComparison.OrdinalIgnoreCase);
if (_linkerEnabled)
@@ -60,23 +63,25 @@ partial void InitializeMetadataUpdater()
});
}
-
- private bool MetadataUpdatesEnabled
+ private bool BuildMetadataUpdatesEnabled()
{
- get
- {
- var unoRuntimeIdentifier = GetMSBuildProperty("UnoRuntimeIdentifier");
- var targetFramework = GetMSBuildProperty("TargetFramework");
- var buildingInsideVisualStudio = GetMSBuildProperty("BuildingInsideVisualStudio");
-
- return
- buildingInsideVisualStudio.Equals("true", StringComparison.OrdinalIgnoreCase)
- && (
- // As of VS 17.8, when the debugger is not attached, mobile targets can use
- // DevServer's hotreload workspace, as visual studio does not enable it on its own.
- (!Debugger.IsAttached
- && (targetFramework.Contains("-android") || targetFramework.Contains("-ios"))));
- }
+ var unoRuntimeIdentifier = GetMSBuildProperty("UnoRuntimeIdentifier");
+ //var targetFramework = GetMSBuildProperty("TargetFramework");
+ //var buildingInsideVisualStudio = GetMSBuildProperty("BuildingInsideVisualStudio");
+
+ return (_forcedHotReloadMode is HotReloadMode.MetadataUpdates or HotReloadMode.Partial)
+ || unoRuntimeIdentifier.Equals("skia", StringComparison.OrdinalIgnoreCase)
+ // Disabled until https://github.com/dotnet/runtime/issues/93860 is fixed
+ //
+ //||
+ //(
+ // buildingInsideVisualStudio.Equals("true", StringComparison.OrdinalIgnoreCase)
+ // && (
+ // // As of VS 17.8, when the debugger is not attached, mobile targets can use
+ // // DevServer's hotreload workspace, as visual studio does not enable it on its own.
+ // (!Debugger.IsAttached
+ // && (targetFramework.Contains("-android") || targetFramework.Contains("-ios")))))
+ ;
}
private string[] GetMetadataUpdateCapabilities()
@@ -153,7 +158,7 @@ private void AssemblyReload(AssemblyDeltaReload assemblyDeltaReload)
UpdatedTypes = ReadIntArray(changedTypesReader)
};
- _agent.ApplyDeltas(new[] { delta });
+ _agent?.ApplyDeltas(new[] { delta });
if (this.Log().IsEnabled(LogLevel.Trace))
{
diff --git a/src/Uno.UI.RemoteControl/HotReload/ClientHotReloadProcessor.Common.cs b/src/Uno.UI.RemoteControl/HotReload/ClientHotReloadProcessor.Common.cs
new file mode 100644
index 000000000000..08bbafdf7379
--- /dev/null
+++ b/src/Uno.UI.RemoteControl/HotReload/ClientHotReloadProcessor.Common.cs
@@ -0,0 +1,136 @@
+#nullable enable
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Text;
+using System.Threading.Tasks;
+using Uno.Extensions;
+using Uno.Foundation.Logging;
+using Uno.UI.Extensions;
+using Uno.UI.Helpers;
+using Uno.UI.RemoteControl.HotReload;
+using Windows.Storage.Pickers.Provider;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Markup;
+using Windows.UI.Xaml.Media;
+
+#if __IOS__
+using UIKit;
+#elif __MACOS__
+using AppKit;
+#elif __ANDROID__
+using Uno.UI;
+#endif
+
+[assembly: System.Reflection.Metadata.MetadataUpdateHandler(typeof(Uno.UI.RemoteControl.HotReload.ClientHotReloadProcessor))]
+
+namespace Uno.UI.RemoteControl.HotReload
+{
+ partial class ClientHotReloadProcessor
+ {
+ private static async IAsyncEnumerable EnumerateHotReloadInstances(
+ object? instance,
+ Func> predicate,
+ string? parentKey)
+ {
+
+ if (instance is FrameworkElement fe)
+ {
+ var instanceTypeName = (instance.GetType().GetOriginalType() ?? instance.GetType()).Name;
+ var instanceKey = parentKey is not null ? $"{parentKey}_{instanceTypeName}" : instanceTypeName;
+ var match = await predicate(fe, instanceKey);
+ if (match is not null)
+ {
+ yield return match;
+ }
+
+ var idx = 0;
+ foreach (var child in fe.EnumerateChildren())
+ {
+ var inner = EnumerateHotReloadInstances(child, predicate, $"{instanceKey}_[{idx}]");
+ idx++;
+ await foreach (var validElement in inner)
+ {
+ yield return validElement;
+ }
+ }
+ }
+ }
+
+ private static void SwapViews(FrameworkElement oldView, FrameworkElement newView)
+ {
+ if (_log.IsEnabled(LogLevel.Trace))
+ {
+ _log.Trace($"Swapping view {newView.GetType()}");
+ }
+
+#if !WINUI
+ var parentAsContentControl = oldView.GetVisualTreeParent() as ContentControl;
+ parentAsContentControl = parentAsContentControl ?? (oldView.GetVisualTreeParent() as ContentPresenter)?.FindFirstParent();
+#else
+ var parentAsContentControl = VisualTreeHelper.GetParent(oldView) as ContentControl;
+ parentAsContentControl = parentAsContentControl ?? (VisualTreeHelper.GetParent(oldView) as ContentPresenter)?.FindFirstParent();
+#endif
+
+ if ((parentAsContentControl?.Content as FrameworkElement) == oldView)
+ {
+ parentAsContentControl.Content = newView;
+ }
+ else if (newView is Page newPage && oldView is Page oldPage)
+ {
+ // In the case of Page, swapping the actual page is not supported, so we
+ // need to swap the content of the page instead. This can happen if the Frame
+ // is using a native presenter which does not use the `Frame.Content` property.
+
+ // Clear any local context, so that the new page can inherit the value coming
+ // from the parent Frame. It may happen if the old page set it explicitly.
+
+#if !WINUI
+ oldPage.ClearValue(Page.DataContextProperty, DependencyPropertyValuePrecedences.Local);
+#else
+ oldPage.ClearValue(Page.DataContextProperty);
+#endif
+
+ oldPage.Content = newPage;
+#if !WINUI
+ newPage.Frame = oldPage.Frame;
+#endif
+ }
+#if !WINUI
+ // Currently we don't have SwapViews implementation that works with WinUI
+ // so skip swapping non-Page views initially for WinUI
+ else
+ {
+ VisualTreeHelper.SwapViews(oldView, newView);
+ }
+#endif
+
+ if (oldView is FrameworkElement oldViewAsFE && newView is FrameworkElement newViewAsFE)
+ {
+ PropagateProperties(oldViewAsFE, newViewAsFE);
+ }
+ }
+
+ private static void PropagateProperties(FrameworkElement oldView, FrameworkElement newView)
+ {
+ if (oldView == null || newView == null)
+ {
+ return;
+ }
+
+ if (newView.DataContext is null
+ && oldView.DataContext is not null)
+ {
+ // If the DataContext is not provided by the page itself, it may
+ // have been provided by an external actor. Copy the value as is
+ // in the DataContext of the new element.
+
+ newView.DataContext = oldView.DataContext;
+ }
+ }
+ }
+}
diff --git a/src/Uno.UI.RemoteControl/HotReload/ClientHotReloadProcessor.PartialReload.cs b/src/Uno.UI.RemoteControl/HotReload/ClientHotReloadProcessor.PartialReload.cs
index dd6d190328b3..bb8dcb191492 100644
--- a/src/Uno.UI.RemoteControl/HotReload/ClientHotReloadProcessor.PartialReload.cs
+++ b/src/Uno.UI.RemoteControl/HotReload/ClientHotReloadProcessor.PartialReload.cs
@@ -32,15 +32,20 @@ private void InitializePartialReload()
_supportsLightweightHotReload =
buildingInsideVisualStudio.Equals("true", StringComparison.OrdinalIgnoreCase)
+ && (_forcedHotReloadMode is null || _forcedHotReloadMode == HotReloadMode.Partial)
&& (
// As of VS 17.8, when the debugger is attached, mobile targets don't invoke MetadataUpdateHandlers
// and both targets are not providing updated types. We simulate parts of this process
// to determine which types have been updated, particularly those with "CreateNewOnMetadataUpdate".
- (Debugger.IsAttached
- && (targetFramework.Contains("-android") || targetFramework.Contains("-ios")))
+ //
+ // Disabled until https://github.com/dotnet/runtime/issues/93860 is fixed
+ //
+ //(Debugger.IsAttached
+ // && (targetFramework.Contains("-android") || targetFramework.Contains("-ios")))
+ //||
// WebAssembly does not support sending updated types, and does not support debugger based hot reload.
- || (unoRuntimeIdentifier?.Equals("WebAssembly", StringComparison.OrdinalIgnoreCase) ?? false));
+ (unoRuntimeIdentifier?.Equals("WebAssembly", StringComparison.OrdinalIgnoreCase) ?? false));
if (this.Log().IsEnabled(LogLevel.Trace))
{
@@ -56,18 +61,6 @@ private void InitializePartialReload()
: new();
}
- private string GetMSBuildProperty(string property, string defaultValue = "")
- {
- var output = defaultValue;
-
- if (_msbuildProperties is not null && !_msbuildProperties.TryGetValue(property, out output))
- {
- return defaultValue;
- }
-
- return output;
- }
-
private async Task PartialReload(FileReload fileReload)
{
if (!_supportsLightweightHotReload)
@@ -161,14 +154,17 @@ private async Task ObserveUpdateTypeMapping()
this.Log().Trace($"Found {newTypes.Length} updated types ({types})");
}
- var actions = _agent.GetMetadataUpdateHandlerActions();
+ if (_agent is not null)
+ {
+ var actions = _agent.GetMetadataUpdateHandlerActions();
- actions.ClearCache.ForEach(a => a(newTypes));
- actions.UpdateApplication.ForEach(a => a(newTypes));
+ actions.ClearCache.ForEach(a => a(newTypes));
+ actions.UpdateApplication.ForEach(a => a(newTypes));
- if (this.Log().IsEnabled(LogLevel.Trace))
- {
- this.Log().Trace($"ObserveUpdateTypeMapping: Invoked metadata updaters");
+ if (this.Log().IsEnabled(LogLevel.Trace))
+ {
+ this.Log().Trace($"ObserveUpdateTypeMapping: Invoked metadata updaters");
+ }
}
return;
diff --git a/src/Uno.UI.RemoteControl/HotReload/ClientHotReloadProcessor.Xaml.cs b/src/Uno.UI.RemoteControl/HotReload/ClientHotReloadProcessor.Xaml.cs
index 08bbafdf7379..2e5b3b352436 100644
--- a/src/Uno.UI.RemoteControl/HotReload/ClientHotReloadProcessor.Xaml.cs
+++ b/src/Uno.UI.RemoteControl/HotReload/ClientHotReloadProcessor.Xaml.cs
@@ -1,22 +1,27 @@
-#nullable enable
-
-using System;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
+using Newtonsoft.Json;
using Uno.Extensions;
using Uno.Foundation.Logging;
using Uno.UI.Extensions;
using Uno.UI.Helpers;
using Uno.UI.RemoteControl.HotReload;
+using Uno.UI.RemoteControl.HotReload.Messages;
using Windows.Storage.Pickers.Provider;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Markup;
using Windows.UI.Xaml.Media;
+#if __IOS__
+using _View = UIKit.UIView;
+#else
+using _View = Windows.UI.Xaml.FrameworkElement;
+#endif
#if __IOS__
using UIKit;
@@ -32,104 +37,139 @@ namespace Uno.UI.RemoteControl.HotReload
{
partial class ClientHotReloadProcessor
{
- private static async IAsyncEnumerable EnumerateHotReloadInstances(
- object? instance,
- Func> predicate,
- string? parentKey)
- {
+ private string? _lastUpdatedFilePath;
- if (instance is FrameworkElement fe)
+ private void ReloadFileWithXamlReader(FileReload fileReload)
+ {
+ if (!fileReload.IsValid())
{
- var instanceTypeName = (instance.GetType().GetOriginalType() ?? instance.GetType()).Name;
- var instanceKey = parentKey is not null ? $"{parentKey}_{instanceTypeName}" : instanceTypeName;
- var match = await predicate(fe, instanceKey);
- if (match is not null)
+ if (fileReload.FilePath.IsNullOrEmpty() && this.Log().IsEnabled(LogLevel.Debug))
{
- yield return match;
+ this.Log().LogDebug($"FileReload is missing a file path");
}
- var idx = 0;
- foreach (var child in fe.EnumerateChildren())
+ if (fileReload.Content is null && this.Log().IsEnabled(LogLevel.Debug))
{
- var inner = EnumerateHotReloadInstances(child, predicate, $"{instanceKey}_[{idx}]");
- idx++;
- await foreach (var validElement in inner)
- {
- yield return validElement;
- }
+ this.Log().LogDebug($"FileReload is missing content");
}
+
+ return;
}
+
+ _lastUpdatedFilePath = fileReload.FilePath;
+
+ _ = Windows.ApplicationModel.Core.CoreApplication.MainView.Dispatcher.RunAsync(
+ Windows.UI.Core.CoreDispatcherPriority.Normal,
+ async () =>
+ {
+ await ReloadWithFileAndContent(fileReload.FilePath, fileReload.Content);
+
+ RemoteControlClient.Instance?.NotifyOfEvent(nameof(FileReload), fileReload.FilePath);
+ });
}
- private static void SwapViews(FrameworkElement oldView, FrameworkElement newView)
+ private async Task ReloadWithFileAndContent(string filePath, string fileContent)
{
- if (_log.IsEnabled(LogLevel.Trace))
+ try
{
- _log.Trace($"Swapping view {newView.GetType()}");
- }
+ if (this.Log().IsEnabled(LogLevel.Debug))
+ {
+ this.Log().LogDebug($"XamlReader reloading changed file [{filePath}]");
+ }
-#if !WINUI
- var parentAsContentControl = oldView.GetVisualTreeParent() as ContentControl;
- parentAsContentControl = parentAsContentControl ?? (oldView.GetVisualTreeParent() as ContentPresenter)?.FindFirstParent();
-#else
- var parentAsContentControl = VisualTreeHelper.GetParent(oldView) as ContentControl;
- parentAsContentControl = parentAsContentControl ?? (VisualTreeHelper.GetParent(oldView) as ContentPresenter)?.FindFirstParent();
-#endif
+ var uri = new Uri("file:///" + filePath.Replace('\\', '/'));
- if ((parentAsContentControl?.Content as FrameworkElement) == oldView)
- {
- parentAsContentControl.Content = newView;
- }
- else if (newView is Page newPage && oldView is Page oldPage)
- {
- // In the case of Page, swapping the actual page is not supported, so we
- // need to swap the content of the page instead. This can happen if the Frame
- // is using a native presenter which does not use the `Frame.Content` property.
+ Application.RegisterComponent(uri, fileContent);
- // Clear any local context, so that the new page can inherit the value coming
- // from the parent Frame. It may happen if the old page set it explicitly.
+ bool IsSameBaseUri(FrameworkElement i)
+ {
+ return uri.OriginalString == i.DebugParseContext?.LocalFileUri
-#if !WINUI
- oldPage.ClearValue(Page.DataContextProperty, DependencyPropertyValuePrecedences.Local);
-#else
- oldPage.ClearValue(Page.DataContextProperty);
-#endif
+ // Compatibility with older versions of Uno, where BaseUri is set to the
+ // local file path instead of the component Uri.
+ || uri.OriginalString == i.BaseUri?.OriginalString;
+ }
- oldPage.Content = newPage;
-#if !WINUI
- newPage.Frame = oldPage.Frame;
-#endif
+ foreach (var instance in EnumerateInstances(Window.Current.Content, IsSameBaseUri).OfType())
+ {
+ if (XamlReader.LoadUsingXClass(fileContent, uri.ToString()) is FrameworkElement newContent)
+ {
+ SwapViews(instance, newContent);
+ }
+ }
+
+ if (ResourceResolver.RetrieveDictionaryForFilePath(uri.AbsolutePath) is { } targetDictionary)
+ {
+ var replacementDictionary = (ResourceDictionary)XamlReader.Load(fileContent);
+ targetDictionary.CopyFrom(replacementDictionary);
+ Application.Current.UpdateResourceBindingsForHotReload();
+ }
}
-#if !WINUI
- // Currently we don't have SwapViews implementation that works with WinUI
- // so skip swapping non-Page views initially for WinUI
- else
+ catch (Exception e)
{
- VisualTreeHelper.SwapViews(oldView, newView);
- }
-#endif
+ if (e is TargetInvocationException { InnerException: { } innerException })
+ {
+ e = innerException;
+ }
- if (oldView is FrameworkElement oldViewAsFE && newView is FrameworkElement newViewAsFE)
- {
- PropagateProperties(oldViewAsFE, newViewAsFE);
+ if (this.Log().IsEnabled(LogLevel.Error))
+ {
+ this.Log().LogError($"Failed reloading changed file [{filePath}]", e);
+ }
+
+ await _rcClient.SendMessage(
+ new HotReload.Messages.XamlLoadError(
+ filePath: filePath,
+ exceptionType: e.GetType().ToString(),
+ message: e.Message,
+ stackTrace: e.StackTrace));
}
}
- private static void PropagateProperties(FrameworkElement oldView, FrameworkElement newView)
+ private static IEnumerable EnumerateInstances(object instance, Func predicate)
{
- if (oldView == null || newView == null)
+ if (instance is FrameworkElement fe && predicate(fe))
{
- return;
+ yield return fe;
}
-
- if (newView.DataContext is null
- && oldView.DataContext is not null)
+ else if (instance != null)
{
- // If the DataContext is not provided by the page itself, it may
- // have been provided by an external actor. Copy the value as is
- // in the DataContext of the new element.
+ IEnumerable> Dig()
+ {
+ switch (instance)
+ {
+ case Panel panel:
+ foreach (var child in panel.Children)
+ {
+ yield return EnumerateInstances(child, predicate);
+ }
+ break;
+
+ case Border border:
+ yield return EnumerateInstances(border.Child, predicate);
+ break;
+
+ case ContentControl control when control.ContentTemplateRoot != null || control.Content != null:
+ yield return EnumerateInstances(control.ContentTemplateRoot ?? control.Content, predicate);
+ break;
+
+ case Control control:
+ yield return EnumerateInstances(control.TemplatedRoot, predicate);
+ break;
+
+ case ContentPresenter presenter:
+ yield return EnumerateInstances(presenter.Content, predicate);
+ break;
+ }
+ }
- newView.DataContext = oldView.DataContext;
+ foreach (var inner in Dig())
+ {
+ foreach (var validElement in inner)
+ {
+ yield return validElement;
+ }
+ }
}
}
}
diff --git a/src/Uno.UI.RemoteControl/HotReload/ClientHotReloadProcessor.cs b/src/Uno.UI.RemoteControl/HotReload/ClientHotReloadProcessor.cs
index 467e1752a3e7..8064dd77df2f 100644
--- a/src/Uno.UI.RemoteControl/HotReload/ClientHotReloadProcessor.cs
+++ b/src/Uno.UI.RemoteControl/HotReload/ClientHotReloadProcessor.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
@@ -19,13 +20,13 @@ public partial class ClientHotReloadProcessor : IRemoteControlProcessor
private string? _projectPath;
private string[]? _xamlPaths;
private readonly IRemoteControlClient _rcClient;
+ private HotReloadMode? _forcedHotReloadMode;
private Dictionary? _msbuildProperties;
public ClientHotReloadProcessor(IRemoteControlClient rcClient)
{
_rcClient = rcClient;
- InitializeMetadataUpdater();
}
partial void InitializeMetadataUpdater();
@@ -44,7 +45,7 @@ public async Task ProcessFrame(Messages.Frame frame)
break;
case FileReload.Name:
- await PartialReload(JsonConvert.DeserializeObject(frame.Content)!);
+ await ProcessFileReload(JsonConvert.DeserializeObject(frame.Content)!);
break;
case HotReloadWorkspaceLoadResult.Name:
@@ -62,6 +63,18 @@ public async Task ProcessFrame(Messages.Frame frame)
return;
}
+ private async Task ProcessFileReload(HotReload.Messages.FileReload fileReload)
+ {
+ if ((!_supportsLightweightHotReload && !_metadataUpdatesEnabled) || _forcedHotReloadMode == HotReloadMode.XamlReader)
+ {
+ ReloadFileWithXamlReader(fileReload);
+ }
+ else
+ {
+ await PartialReload(fileReload);
+ }
+ }
+
private async Task ConfigureServer()
{
var assembly = _rcClient.AppType.Assembly;
@@ -88,11 +101,13 @@ private async Task ConfigureServer()
_msbuildProperties = Messages.ConfigureServer.BuildMSBuildProperties(config.MSBuildProperties);
- ConfigureServer message = new(_projectPath, _xamlPaths, GetMetadataUpdateCapabilities(), MetadataUpdatesEnabled, config.MSBuildProperties);
+ ConfigureHotReloadMode();
+ InitializeMetadataUpdater();
+ InitializePartialReload();
- await _rcClient.SendMessage(message);
+ ConfigureServer message = new(_projectPath, _xamlPaths, GetMetadataUpdateCapabilities(), _metadataUpdatesEnabled, config.MSBuildProperties);
- InitializePartialReload();
+ await _rcClient.SendMessage(message);
}
else
{
@@ -102,4 +117,36 @@ private async Task ConfigureServer()
}
}
}
+
+ private void ConfigureHotReloadMode()
+ {
+ var unoHotReloadMode = GetMSBuildProperty("UnoHotReloadMode");
+
+ if (!string.IsNullOrEmpty(unoHotReloadMode))
+ {
+ if (!Enum.TryParse(unoHotReloadMode, true, out var hotReloadMode))
+ {
+ throw new NotSupportedException($"The hot reload mode {unoHotReloadMode} is not supported.");
+ }
+
+ _forcedHotReloadMode = hotReloadMode;
+
+ if (this.Log().IsEnabled(LogLevel.Trace))
+ {
+ this.Log().Trace($"Forced Hot Reload Mode:{_forcedHotReloadMode}");
+ }
+ }
+ }
+
+ private string GetMSBuildProperty(string property, string defaultValue = "")
+ {
+ var output = defaultValue;
+
+ if (_msbuildProperties is not null && !_msbuildProperties.TryGetValue(property, out output))
+ {
+ return defaultValue;
+ }
+
+ return output;
+ }
}
diff --git a/src/Uno.UI.RemoteControl/HotReload/HotReloadMode.cs b/src/Uno.UI.RemoteControl/HotReload/HotReloadMode.cs
new file mode 100644
index 000000000000..d74417f72450
--- /dev/null
+++ b/src/Uno.UI.RemoteControl/HotReload/HotReloadMode.cs
@@ -0,0 +1,24 @@
+namespace Uno.UI.RemoteControl.HotReload;
+
+internal enum HotReloadMode
+{
+ ///
+ /// Hot reload is not configured
+ ///
+ None = 0,
+
+ ///
+ /// Hot reload using Metadata updates
+ ///
+ MetadataUpdates,
+
+ ///
+ /// Hot Reload using partial updated types discovery
+ ///
+ Partial,
+
+ ///
+ /// Hot Reload using XAML reader
+ ///
+ XamlReader,
+}
diff --git a/src/Uno.UI.Toolkit/Uno.UI.Toolkit.Windows.csproj b/src/Uno.UI.Toolkit/Uno.UI.Toolkit.Windows.csproj
index d2d0dc65608d..024026ba7e99 100644
--- a/src/Uno.UI.Toolkit/Uno.UI.Toolkit.Windows.csproj
+++ b/src/Uno.UI.Toolkit/Uno.UI.Toolkit.Windows.csproj
@@ -36,7 +36,7 @@
-
+