diff --git a/src/Caliburn.Micro.Platform/Action.cs b/src/Caliburn.Micro.Platform/Action.cs index 376756a5..0c8eb650 100644 --- a/src/Caliburn.Micro.Platform/Action.cs +++ b/src/Caliburn.Micro.Platform/Action.cs @@ -12,8 +12,8 @@ namespace Caliburn.Micro using System.Reflection; #elif WinUI3 using System.Linq; - using Microsoft.UI.Xaml; using System.Reflection; + using Microsoft.UI.Xaml; #elif XFORMS using UIElement = global::Xamarin.Forms.Element; using FrameworkElement = global::Xamarin.Forms.VisualElement; @@ -174,7 +174,8 @@ public static void Invoke(object target, string methodName, DependencyObject vie Message = message, View = view, Source = source, - EventArgs = eventArgs + EventArgs = eventArgs, + SkipAvailabilityResolution = Message.GetSkipAvailabilityResolution(view) }; if (parameters != null) diff --git a/src/Caliburn.Micro.Platform/ActionExecutionContext.cs b/src/Caliburn.Micro.Platform/ActionExecutionContext.cs index 88e951dd..fb938ed8 100644 --- a/src/Caliburn.Micro.Platform/ActionExecutionContext.cs +++ b/src/Caliburn.Micro.Platform/ActionExecutionContext.cs @@ -33,7 +33,8 @@ namespace Caliburn.Micro /// /// The context used during the execution of an Action or its guard. /// - public class ActionExecutionContext : IDisposable { + public class ActionExecutionContext : IDisposable + { private WeakReference _message; private WeakReference _source; private WeakReference _target; @@ -51,15 +52,26 @@ public class ActionExecutionContext : IDisposable { /// public object EventArgs; + /// + /// Gets or sets a value indicating whether to skip availability resolution. + /// + public bool SkipAvailabilityResolution + { + get => _skipAvailabilityResolution; + set => _skipAvailabilityResolution = value; + } + /// /// The actual method info to be invoked. /// public MethodInfo Method; + private bool _skipAvailabilityResolution; /// /// The message being executed. /// - public ActionMessage Message { + public ActionMessage Message + { get { return _message == null ? null : _message.Target as ActionMessage; } set { _message = new WeakReference(value); } } @@ -67,7 +79,8 @@ public ActionMessage Message { /// /// The source from which the message originates. /// - public FrameworkElement Source { + public FrameworkElement Source + { get { return _source == null ? null : _source.Target as FrameworkElement; } set { _source = new WeakReference(value); } } @@ -75,7 +88,8 @@ public FrameworkElement Source { /// /// The instance on which the action is invoked. /// - public object Target { + public object Target + { get { return _target == null ? null : _target.Target; } set { _target = new WeakReference(value); } } @@ -83,7 +97,8 @@ public object Target { /// /// The view associated with the target. /// - public DependencyObject View { + public DependencyObject View + { get { return _view == null ? null : _view.Target as DependencyObject; } set { _view = new WeakReference(value); } } @@ -93,8 +108,10 @@ public DependencyObject View { /// /// The data key. /// Custom data associated with the context. - public object this[string key] { - get { + public object this[string key] + { + get + { if (_values == null) _values = new Dictionary(); @@ -103,7 +120,8 @@ public object this[string key] { return result; } - set { + set + { if (_values == null) _values = new Dictionary(); @@ -114,7 +132,8 @@ public object this[string key] { /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// - public void Dispose() { + public void Dispose() + { Disposing(this, System.EventArgs.Empty); } diff --git a/src/Caliburn.Micro.Platform/ActionMessage.cs b/src/Caliburn.Micro.Platform/ActionMessage.cs index 8e09cf48..a55d1518 100644 --- a/src/Caliburn.Micro.Platform/ActionMessage.cs +++ b/src/Caliburn.Micro.Platform/ActionMessage.cs @@ -161,6 +161,8 @@ public string MethodName set { SetValue(MethodNameProperty, value); } } + public bool SkipAvailabilityResolution { get; set; } + /// /// Gets the parameters to pass as part of the method invocation. /// @@ -315,8 +317,9 @@ void ElementLoaded(object sender, RoutedEventArgs e) Log.Info($"Binding {binding.Source}"); #elif (NET || CAL_NETCORE) && !WinUI3 && !WINDOWS_UWP - var binding = new Binding { - Path = new PropertyPath(Message.HandlerProperty), + var binding = new Binding + { + Path = new PropertyPath(Message.HandlerProperty), Source = currentElement }; #elif WINDOWS_UWP || WinUI3 @@ -365,7 +368,8 @@ void UpdateContext() _context = new ActionExecutionContext { Message = this, - Source = AssociatedObject + Source = AssociatedObject, + SkipAvailabilityResolution = SkipAvailabilityResolution }; PrepareContext(_context); @@ -528,7 +532,6 @@ public override string ToString() Log.Info($"context.CanExecute is null {context.CanExecute == null} "); if (context.CanExecute != null) { - Log.Info("HERE"); Log.Info($"ApplyAvailabilityEffect CanExecute {context.Method.Name}"); source.IsEnabled = context.CanExecute(); } @@ -536,7 +539,23 @@ public override string ToString() if (!hasBinding && context.CanExecute != null) { Log.Info($"ApplyAvailabilityEffect CanExecute {context.CanExecute()} - {context.Method.Name}"); - source.IsEnabled = context.CanExecute(); + if (!context.SkipAvailabilityResolution) + { + Log.Info($"ApplyAvailabilityEffect CanExecute {context.CanExecute()} - {context.Method.Name} - {source.Name}"); + source.IsEnabled = context.CanExecute(); + } + else + { + Log.Info("Skipping IsEnabled source because source Name is not set"); + } + if (!source.IsEnabled) + { + Log.Info($"Disabled {source.Name}"); + } + else + { + Log.Info($"Enabled {source.Name}"); + } } #endif Log.Info($"ApplyAvailabilityEffect source enabled {source.IsEnabled}"); @@ -615,6 +634,7 @@ public override string ToString() } } #else + if (source != null && source.DataContext != null) { var target = source.DataContext; diff --git a/src/Caliburn.Micro.Platform/Message.cs b/src/Caliburn.Micro.Platform/Message.cs index 658e4e8e..45bcd117 100644 --- a/src/Caliburn.Micro.Platform/Message.cs +++ b/src/Caliburn.Micro.Platform/Message.cs @@ -50,6 +50,7 @@ namespace Caliburn.Micro /// public static class Message { + internal const string Skip_Availability_Resolution = "SkipAvailabilityResolution"; internal static readonly DependencyProperty HandlerProperty = #if AVALONIA AvaloniaProperty.RegisterAttached("Handler", typeof(Message)); @@ -107,11 +108,28 @@ public static object GetHandler(DependencyObject d) "Attach", typeof(string), typeof(Message), - null, + null, OnAttachChanged ); #endif + /// + /// A property definition representing whether should check if the function can be executed + /// + public static readonly DependencyProperty SkipAvailabilityResolutionProperty = +#if AVALONIA + AvaloniaProperty.RegisterAttached(Skip_Availability_Resolution, typeof(Message)); +#else + DependencyPropertyHelper.RegisterAttached( + Skip_Availability_Resolution, + typeof(string), + typeof(Message), + null, + OnAttachChanged + ); +#endif + + #if AVALONIA static Message() { @@ -138,6 +156,29 @@ public static string GetAttach(DependencyObject d) return d.GetValue(AttachProperty) as string; } + /// + /// Sets the attached triggers and messages. + /// + /// The element to attach to. + /// The parsable attachment text. + public static void SetSkipAvailabilityResolution(DependencyObject d, string skip) + { + d.SetValue(SkipAvailabilityResolutionProperty, skip); + } + + /// + /// Gets the attached triggers and messages. + /// + /// The element that was attached to. + /// The parsable attachment text. + public static bool GetSkipAvailabilityResolution(DependencyObject d) + { + var value = d.GetValue(SkipAvailabilityResolutionProperty) as string; + if (!bool.TryParse(value, out bool result)) + result = false; + return result; + } + static void OnAttachChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (object.ReferenceEquals(e.NewValue, e.OldValue)) @@ -162,7 +203,8 @@ static void OnAttachChanged(DependencyObject d, DependencyPropertyChangedEventAr var allTriggers = visualElement != null ? visualElement.Triggers : new List(); - if (messageTriggers != null) { + if (messageTriggers != null) + { messageTriggers.Apply(x => allTriggers.Remove(x)); } diff --git a/src/Caliburn.Micro.Platform/Parser.cs b/src/Caliburn.Micro.Platform/Parser.cs index 5db13223..f49c0c69 100644 --- a/src/Caliburn.Micro.Platform/Parser.cs +++ b/src/Caliburn.Micro.Platform/Parser.cs @@ -76,7 +76,7 @@ public static class Parser /// The message text. /// The triggers parsed from the text. #if AVALONIA - public static IEnumerable Parse(DependencyObject target, string text) + public static IEnumerable Parse(DependencyObject target, string text) #else public static IEnumerable Parse(DependencyObject target, string text) #endif @@ -232,7 +232,7 @@ private static void AddActionToTrigger(DependencyObject target, TriggerAction me /// /// The parameters passed to the method are the the target of the trigger and string representing the trigger. public static Func CreateTrigger = (target, triggerText) => - + #else /// /// The function used to generate a trigger. @@ -302,7 +302,7 @@ public static TriggerAction CreateMessage(DependencyObject target, string messag /// public static Func InterpretMessageText = (target, text) => { - return new ActionMessage { MethodName = Regex.Replace(text, "^Action", string.Empty).Trim() }; + return new ActionMessage { MethodName = Regex.Replace(text, "^Action", string.Empty).Trim(), SkipAvailabilityResolution = Message.GetSkipAvailabilityResolution(target) }; }; /// diff --git a/src/Caliburn.Micro.Platform/Platforms/Maui/ActionMessage.cs b/src/Caliburn.Micro.Platform/Platforms/Maui/ActionMessage.cs index 8c3bd56d..ec89b25b 100644 --- a/src/Caliburn.Micro.Platform/Platforms/Maui/ActionMessage.cs +++ b/src/Caliburn.Micro.Platform/Platforms/Maui/ActionMessage.cs @@ -49,6 +49,7 @@ public ActionMessage() /// The name of the method. public string MethodName { get; set; } + public bool SkipAvailabilityResolution { get; set; } /// /// The handler for the action. /// diff --git a/src/Caliburn.Micro.Platform/Platforms/Xamarin.Forms/ActionMessage.cs b/src/Caliburn.Micro.Platform/Platforms/Xamarin.Forms/ActionMessage.cs index 2b7258dc..a191ad9b 100644 --- a/src/Caliburn.Micro.Platform/Platforms/Xamarin.Forms/ActionMessage.cs +++ b/src/Caliburn.Micro.Platform/Platforms/Xamarin.Forms/ActionMessage.cs @@ -32,6 +32,7 @@ public class ActionMessage : TriggerActionBase, IHaveParameters /// True by default. public static bool ThrowsExceptions = true; + public bool SkipAvailabilityResolution { get; set; } = false; /// /// Creates an instance of . ///