diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 8809a6b8..0d494207 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -40,7 +40,7 @@ jobs: - name: Setup NuGet.exe for use with actions # You may pin to the exact commit or the version. # uses: NuGet/setup-nuget@fd9fffd6ca4541cf4152a9565835ca1a88a6eb37 - uses: NuGet/setup-nuget@v1.1.1 + uses: NuGet/setup-nuget@v2 - name: Add msbuild to PATH uses: microsoft/setup-msbuild@v2 @@ -81,5 +81,5 @@ jobs: run: msbuild ${{env.caliburn_sln}} /t:package /p:Configuration=${{env.build_configuration}} - name: publish Nuget Packages to GitHub - run: dotnet nuget publish ${{env.nuget_folder}} --source ${{env.package_feed}} --api-key ${{secrets.PUBLISH_NUGET_PACKAGE}} --skip-duplicate + run: dotnet nuget push ${{env.nuget_folder}} --source ${{env.package_feed}} --api-key ${{secrets.PUBLISH_NUGET_PACKAGE}} --skip-duplicate if: github.event_name != 'pull_request' diff --git a/src/Caliburn.Micro.Core/AsyncEventHandler.cs b/src/Caliburn.Micro.Core/AsyncEventHandler.cs index f92776d5..9e76af37 100644 --- a/src/Caliburn.Micro.Core/AsyncEventHandler.cs +++ b/src/Caliburn.Micro.Core/AsyncEventHandler.cs @@ -3,6 +3,13 @@ namespace Caliburn.Micro { + /// + /// Represents an asynchronous event handler. + /// + /// The type of the event data generated by the event. + /// The source of the event. + /// An object that contains the event data. + /// A task that represents the asynchronous operation. public delegate Task AsyncEventHandler( object sender, TEventArgs e) diff --git a/src/Caliburn.Micro.Core/AsyncEventHandlerExtensions.cs b/src/Caliburn.Micro.Core/AsyncEventHandlerExtensions.cs index c4b2ecaa..32cfd6e1 100644 --- a/src/Caliburn.Micro.Core/AsyncEventHandlerExtensions.cs +++ b/src/Caliburn.Micro.Core/AsyncEventHandlerExtensions.cs @@ -5,13 +5,33 @@ namespace Caliburn.Micro { + /// + /// AsyncEventHandlerExtensions class. + /// + /// + /// Contains helper functions to run Invoke methods asynchronously. + /// public static class AsyncEventHandlerExtensions { + /// + /// Gets the invocation list of the specified async event handler. + /// + /// The type of the event arguments. + /// The async event handler. + /// An enumerable of async event handlers. public static IEnumerable> GetHandlers( this AsyncEventHandler handler) where TEventArgs : EventArgs => handler.GetInvocationList().Cast>(); + /// + /// Invokes all handlers of the specified async event handler asynchronously. + /// + /// The type of the event arguments. + /// The async event handler. + /// The source of the event. + /// The event data. + /// A task that represents the completion of all handler invocations. public static Task InvokeAllAsync( this AsyncEventHandler handler, object sender, diff --git a/src/Caliburn.Micro.Platform/Platforms/Maui/Windows/MauiPlatformProvider.cs b/src/Caliburn.Micro.Platform/Platforms/Maui/Windows/MauiPlatformProvider.cs index 95f11a38..62a77b4b 100644 --- a/src/Caliburn.Micro.Platform/Platforms/Maui/Windows/MauiPlatformProvider.cs +++ b/src/Caliburn.Micro.Platform/Platforms/Maui/Windows/MauiPlatformProvider.cs @@ -1,54 +1,48 @@ -namespace Caliburn.Micro.Maui +namespace Caliburn.Micro.Maui { using System; using System.Collections.Generic; + using System.Reflection; using System.Threading; using System.Threading.Tasks; - using System.Reflection; - using Windows.UI.Core; - //using Windows.UI.Xaml; - using Microsoft.UI; using Microsoft.UI.Xaml; - + using Windows.UI.Core; /// - /// A implementation for the XAML platfrom. + /// A implementation for the .NET MAUI platform. /// - public class MauiPlatformProvider : IPlatformProvider + public class MauiPlatformProvider : IPlatformProvider { private readonly CoreDispatcher dispatcher; - /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - public MauiPlatformProvider() + public MauiPlatformProvider() { - dispatcher = Window.Current?.Dispatcher; - } /// - /// Whether or not classes should execute property change notications on the UI thread. + /// Whether or not classes should execute property change notifications on the UI thread. /// public virtual bool PropertyChangeNotificationsOnUIThread => true; /// /// Indicates whether or not the framework is in design-time mode. /// - public virtual bool InDesignMode + public virtual bool InDesignMode { get { return View.InDesignMode; } } - private void ValidateDispatcher() + private void ValidateDispatcher() { if (dispatcher == null) throw new InvalidOperationException("Not initialized with dispatcher."); } - private bool CheckAccess() + private bool CheckAccess() { return dispatcher == null || Window.Current != null; } @@ -57,7 +51,7 @@ private bool CheckAccess() /// Executes the action on the UI thread asynchronously. /// /// The action to execute. - public virtual void BeginOnUIThread(System.Action action) + public virtual void BeginOnUIThread(System.Action action) { ValidateDispatcher(); var dummy = dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => action()); @@ -67,23 +61,22 @@ public virtual void BeginOnUIThread(System.Action action) /// Executes the action on the UI thread asynchronously. /// /// The action to execute. - /// - public virtual Task OnUIThreadAsync(Func action) { + /// A task that represents the asynchronous operation. + public virtual Task OnUIThreadAsync(Func action) + { ValidateDispatcher(); return dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => action()).AsTask(); - } /// /// Executes the action on the UI thread. /// /// The action to execute. - /// - public virtual void OnUIThread(System.Action action) + public virtual void OnUIThread(System.Action action) { if (CheckAccess()) action(); - else + else { dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => action()).AsTask().Wait(); } @@ -93,33 +86,31 @@ public virtual void OnUIThread(System.Action action) /// Used to retrieve the root, non-framework-created view. /// /// The view to search. - /// - /// The root element that was not created by the framework. - /// + /// The root element that was not created by the framework. /// /// In certain instances the services create UI elements. /// For example, if you ask the window manager to show a UserControl as a dialog, it creates a window to host the UserControl in. /// The WindowManager marks that element as a framework-created element so that it can determine what it created vs. what was intended by the developer. /// Calling GetFirstNonGeneratedView allows the framework to discover what the original element was. /// - public virtual object GetFirstNonGeneratedView(object view) + public virtual object GetFirstNonGeneratedView(object view) { return View.GetFirstNonGeneratedView(view); } private static readonly DependencyProperty PreviouslyAttachedProperty = DependencyProperty.RegisterAttached( "PreviouslyAttached", - typeof (bool), - typeof (MauiPlatformProvider), + typeof(bool), + typeof(MauiPlatformProvider), null - ); + ); /// - /// Executes the handler the fist time the view is loaded. + /// Executes the handler the first time the view is loaded. /// /// The view. /// The handler. - public virtual void ExecuteOnFirstLoad(object view, Action handler) + public virtual void ExecuteOnFirstLoad(object view, Action handler) { //var element = view as FrameworkElement; //if (element != null && !(bool) element.GetValue(PreviouslyAttachedProperty)) { @@ -133,7 +124,7 @@ public virtual void ExecuteOnFirstLoad(object view, Action handler) /// /// The view. /// The handler. - public virtual void ExecuteOnLayoutUpdated(object view, Action handler) + public virtual void ExecuteOnLayoutUpdated(object view, Action handler) { //var element = view as FrameworkElement; //if (element != null) { @@ -147,31 +138,29 @@ public virtual void ExecuteOnLayoutUpdated(object view, Action handler) /// The view model to close. /// The associated views. /// The dialog result. - /// - /// An to close the view model. - /// - /// + /// An to close the view model. public virtual Func GetViewCloseAction(object viewModel, ICollection views, bool? dialogResult) { - foreach (var contextualView in views) { + foreach (var contextualView in views) + { var viewType = contextualView.GetType(); var closeMethod = viewType.GetRuntimeMethod("Close", new Type[0]); if (closeMethod != null) - return ct => { - + return ct => + { closeMethod.Invoke(contextualView, null); return Task.FromResult(true); }; var isOpenProperty = viewType.GetRuntimeProperty("IsOpen"); - if (isOpenProperty != null) { + if (isOpenProperty != null) + { return ct => { isOpenProperty.SetValue(contextualView, false, null); - return Task.FromResult(true); }; } @@ -185,4 +174,3 @@ public virtual Func GetViewCloseAction(object viewModel } } } - diff --git a/src/Caliburn.Micro.Platform/Platforms/net46-netcore/FrameAdapter.cs b/src/Caliburn.Micro.Platform/Platforms/net46-netcore/FrameAdapter.cs index 13e69adc..d0007861 100644 --- a/src/Caliburn.Micro.Platform/Platforms/net46-netcore/FrameAdapter.cs +++ b/src/Caliburn.Micro.Platform/Platforms/net46-netcore/FrameAdapter.cs @@ -249,6 +249,9 @@ public JournalEntry RemoveBackEntry() return frame.RemoveBackEntry(); } + /// + /// Disposes the FrameAdapter instance, detaching event handlers to prevent memory leaks. + /// public void Dispose() { this.frame.Navigating -= OnNavigating; diff --git a/src/Caliburn.Micro.Platform/Platforms/net46-netcore/WindowConductor.cs b/src/Caliburn.Micro.Platform/Platforms/net46-netcore/WindowConductor.cs index 46c8b79d..478b7012 100644 --- a/src/Caliburn.Micro.Platform/Platforms/net46-netcore/WindowConductor.cs +++ b/src/Caliburn.Micro.Platform/Platforms/net46-netcore/WindowConductor.cs @@ -6,6 +6,9 @@ namespace Caliburn.Micro { + /// + /// Manages the lifecycle of a window and its associated view model. + /// public class WindowConductor { private bool deactivatingFromView; @@ -14,12 +17,21 @@ public class WindowConductor private readonly Window view; private readonly object model; + /// + /// Initializes a new instance of the class. + /// + /// The view model associated with the window. + /// The window being managed. public WindowConductor(object model, Window view) { this.model = model; this.view = view; } + /// + /// Initializes the conductor asynchronously. + /// + /// A task that represents the asynchronous operation. public async Task InitialiseAsync() { if (model is IActivate activator) @@ -39,6 +51,9 @@ public async Task InitialiseAsync() } } + /// + /// Handles the window's Closed event. + /// private async void Closed(object sender, EventArgs e) { view.Closed -= Closed; @@ -56,6 +71,9 @@ private async void Closed(object sender, EventArgs e) deactivatingFromView = false; } + /// + /// Handles the view model's Deactivated event. + /// private Task Deactivated(object sender, DeactivationEventArgs e) { if (!e.WasClosed) @@ -79,6 +97,9 @@ private Task Deactivated(object sender, DeactivationEventArgs e) return Task.FromResult(true); } + /// + /// Handles the window's Closing event. + /// private async void Closing(object sender, CancelEventArgs e) { if (e.Cancel) diff --git a/src/Caliburn.Micro.Platform/Platforms/uap/DispatcherTaskExtensions.cs b/src/Caliburn.Micro.Platform/Platforms/uap/DispatcherTaskExtensions.cs index f1496b63..38476159 100644 --- a/src/Caliburn.Micro.Platform/Platforms/uap/DispatcherTaskExtensions.cs +++ b/src/Caliburn.Micro.Platform/Platforms/uap/DispatcherTaskExtensions.cs @@ -4,10 +4,24 @@ namespace Caliburn.Micro { + /// + /// DispatcherTaskExtensions class. + /// + /// + /// Contains helper functions to run tasks asynchronously on a . + /// public static class DispatcherTaskExtensions { + /// + /// Runs a task asynchronously on the specified . + /// + /// The type of the result produced by the task. + /// The dispatcher on which to run the task. + /// The function that returns the task to be run. + /// The priority with which the task should be run. + /// A task that represents the asynchronous operation. public static async Task RunTaskAsync(this CoreDispatcher dispatcher, - Func> func, CoreDispatcherPriority priority = CoreDispatcherPriority.Normal) + Func> func, CoreDispatcherPriority priority = CoreDispatcherPriority.Normal) { var taskCompletionSource = new TaskCompletionSource(); await dispatcher.RunAsync(priority, async () => @@ -24,7 +38,16 @@ await dispatcher.RunAsync(priority, async () => return await taskCompletionSource.Task; } - // There is no TaskCompletionSource so we use a bool that we throw away. + /// + /// Runs a task asynchronously on the specified . + /// + /// The dispatcher on which to run the task. + /// The function that returns the task to be run. + /// The priority with which the task should be run. + /// A task that represents the asynchronous operation. + /// + /// There is no so a is used and discarded. + /// public static async Task RunTaskAsync(this CoreDispatcher dispatcher, Func func, CoreDispatcherPriority priority = CoreDispatcherPriority.Normal) => await RunTaskAsync(dispatcher, async () => { await func(); return false; }, priority); diff --git a/src/Caliburn.Micro.Platform/Platforms/uap/FrameAdapter.cs b/src/Caliburn.Micro.Platform/Platforms/uap/FrameAdapter.cs index c74d8bef..5f2ca882 100644 --- a/src/Caliburn.Micro.Platform/Platforms/uap/FrameAdapter.cs +++ b/src/Caliburn.Micro.Platform/Platforms/uap/FrameAdapter.cs @@ -435,6 +435,9 @@ private static ApplicationDataContainer GetSettingsContainer() ApplicationDataCreateDisposition.Always); } + /// + /// Disposes the FrameAdapter instance, detaching event handlers to prevent memory leaks. + /// public void Dispose() { this.frame.Navigating -= OnNavigating;