diff --git a/src/HotAvalonia.Extensions/AvaloniaHotReloadExtensions.fs b/src/HotAvalonia.Extensions/AvaloniaHotReloadExtensions.fs new file mode 100644 index 0000000..581f788 --- /dev/null +++ b/src/HotAvalonia.Extensions/AvaloniaHotReloadExtensions.fs @@ -0,0 +1,165 @@ +// +// This file has been automatically added to your project by the "HotAvalonia.Extensions" NuGet package +// (https://nuget.org/packages/HotAvalonia.Extensions). +// +// Please see https://github.com/Kir-Antipov/HotAvalonia for more information. +// + +//#region License +// MIT License +// +// Copyright (c) 2023-2024 Kir_Antipov +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +//#endregion + +#nowarn + +namespace HotAvalonia + +open System +open System.Diagnostics +open System.Diagnostics.CodeAnalysis +open System.IO +open System.Reflection +open System.Runtime.CompilerServices +open System.Runtime.InteropServices +open Avalonia + +/// +/// Indicates that the decorated method should be called whenever the associated Avalonia control is hot reloaded. +/// +/// +/// This attribute is intended to be applied to parameterless instance methods of Avalonia controls. +/// When the control is hot reloaded, the method marked with this attribute is executed. +/// This can be used to refresh or update the control's state in response to hot reload events. +/// +///

+/// +/// The method must meet the following requirements: +/// +/// It must be an instance method (i.e., not static). +/// It must not have any parameters. +/// +/// +/// Example usage: +/// +/// [] +/// let private initialize () = +/// // Code to initialize or refresh +/// // the control during hot reload. +/// () +/// +///
+[] +[] +[] +type internal AvaloniaHotReloadAttribute() = + inherit Attribute() + +/// +/// Provides extension methods for enabling and disabling hot reload functionality for Avalonia applications. +/// +[] +[] +type internal AvaloniaHotReloadExtensions = +#if ENABLE_XAML_HOT_RELOAD && !DISABLE_XAML_HOT_RELOAD + /// + /// A mapping between Avalonia instances and their associated hot reload context. + /// + static let s_apps = ConditionalWeakTable() + + /// + /// Enables hot reload functionality for the given Avalonia application. + /// + /// The Avalonia application instance for which hot reload should be enabled. + /// The file path of the application's main source file. Optional if the method called within the file of interest. + [] + [] + static member EnableHotReload(app: Application, [] appFilePath: string) = + match s_apps.TryGetValue(app) with + | true, context -> context.EnableHotReload() + | _ -> + if not (String.IsNullOrEmpty(appFilePath) || File.Exists(appFilePath)) then + raise (FileNotFoundException("The corresponding XAML file could not be found.", appFilePath)) + + if not (String.IsNullOrEmpty(appFilePath)) then + AvaloniaProjectLocator.AddHint(app.GetType(), appFilePath) + + let appDomainContext = AvaloniaHotReloadContext.FromAppDomain() + let assetContext = AvaloniaHotReloadContext.ForAssets() + let context = HotReloadContext.Combine(appDomainContext, assetContext) + s_apps.Add(app, context) + + context.EnableHotReload() + + /// + /// Enables hot reload functionality for the given Avalonia application. + /// + /// The Avalonia application instance for which hot reload should be enabled. + /// The callback function capable of resolving a project path for a given assembly. + [] + [] + static member EnableHotReload(app: Application, projectPathResolver: Assembly -> string) = + AvaloniaProjectLocator.AddHint(projectPathResolver) + app.EnableHotReload(String.Empty) + + /// + /// Disables hot reload functionality for the given Avalonia application. + /// + /// The Avalonia application instance for which hot reload should be disabled. + [] + [] + static member DisableHotReload(app: Application) = + match s_apps.TryGetValue(app) with + | true, context -> context.DisableHotReload() + | _ -> () +#else + /// + /// Enables hot reload functionality for the given Avalonia application. + /// + /// The Avalonia application instance for which hot reload should be enabled. + /// The file path of the application's main source file. Optional if the method called within the file of interest. + [] + [] + [] + static member EnableHotReload(app: Application, [] appFilePath: string) = + () + + /// + /// Enables hot reload functionality for the given Avalonia application. + /// + /// The Avalonia application instance for which hot reload should be enabled. + /// The callback function capable of resolving a project path for a given assembly. + [] + [] + [] + static member EnableHotReload(app: Application, projectPathResolver: Assembly -> string) = + () + + /// + /// Disables hot reload functionality for the given Avalonia application. + /// + /// The Avalonia application instance for which hot reload should be disabled. + [] + [] + [] + static member DisableHotReload(app: Application) = + () +#endif diff --git a/src/HotAvalonia.Extensions/HotAvalonia.Extensions.csproj b/src/HotAvalonia.Extensions/HotAvalonia.Extensions.csproj index 8f66872..6e55a31 100644 --- a/src/HotAvalonia.Extensions/HotAvalonia.Extensions.csproj +++ b/src/HotAvalonia.Extensions/HotAvalonia.Extensions.csproj @@ -15,6 +15,7 @@ +