From 401966b90597e7a3b7ce371a2164c2c73d86fc9e Mon Sep 17 00:00:00 2001 From: Charles Milette Date: Wed, 4 Jun 2025 20:14:30 -0400 Subject: [PATCH 1/6] Simplify ResourceHelper logic to avoid needing #if --- .../ActionCollection.cs | 2 +- .../BehaviorCollection.cs | 6 +- .../BehaviorOfT.cs | 2 +- .../Core/ResourceHelper.cs | 98 +++++-------------- .../TriggerOfT.cs | 2 +- .../Core/ResourceHelper.cs | 11 +++ .../Microsoft.Xaml.Interactivity.Uwp.csproj | 1 - .../Core/ResourceHelper.cs | 11 +++ .../Core/ResourceHelper.cs | 11 +++ .../Microsoft.Xaml.Interactivity.csproj | 1 + 10 files changed, 63 insertions(+), 82 deletions(-) create mode 100644 src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Uwp/Core/ResourceHelper.cs create mode 100644 src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.WinUI/Core/ResourceHelper.cs create mode 100644 src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity/Core/ResourceHelper.cs diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/ActionCollection.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/ActionCollection.cs index 3daff6d0..5426021c 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/ActionCollection.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/ActionCollection.cs @@ -47,7 +47,7 @@ private static void VerifyType(DependencyObject item) { if (!(item is IAction)) { - throw new InvalidOperationException(ResourceHelper.GetString("NonActionAddedToActionCollectionExceptionMessage")); + throw new InvalidOperationException(ResourceHelper.NonActionAddedToActionCollectionExceptionMessage); } } } diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/BehaviorCollection.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/BehaviorCollection.cs index 9a3129e9..6549b6b3 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/BehaviorCollection.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/BehaviorCollection.cs @@ -60,7 +60,7 @@ public void Attach(DependencyObject associatedObject) if (this.AssociatedObject != null) { - throw new InvalidOperationException(ResourceHelper.GetString("CannotAttachBehaviorMultipleTimesExceptionMessage")); + throw new InvalidOperationException(ResourceHelper.CannotAttachBehaviorMultipleTimesExceptionMessage); } Debug.Assert(associatedObject != null, "The previous checks should keep us from ever setting null here."); @@ -162,12 +162,12 @@ private IBehavior VerifiedAttach(DependencyObject item) IBehavior behavior = item as IBehavior; if (behavior == null) { - throw new InvalidOperationException(ResourceHelper.GetString("NonBehaviorAddedToBehaviorCollectionExceptionMessage")); + throw new InvalidOperationException(ResourceHelper.NonBehaviorAddedToBehaviorCollectionExceptionMessage); } if (this._oldCollection.Contains(behavior)) { - throw new InvalidOperationException(ResourceHelper.GetString("DuplicateBehaviorInCollectionExceptionMessage")); + throw new InvalidOperationException(ResourceHelper.DuplicateBehaviorInCollectionExceptionMessage); } if (this.AssociatedObject != null) diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/BehaviorOfT.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/BehaviorOfT.cs index 4d482b76..731a1a73 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/BehaviorOfT.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/BehaviorOfT.cs @@ -40,7 +40,7 @@ protected override void OnAttached() { string actualType = base.AssociatedObject.GetType().FullName; string expectedType = typeof (T).FullName; - string message = string.Format(ResourceHelper.GetString("InvalidAssociatedObjectExceptionMessage"), actualType, expectedType); + string message = string.Format(ResourceHelper.InvalidAssociatedObjectExceptionMessage, actualType, expectedType); throw new InvalidOperationException(message); } } diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ResourceHelper.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ResourceHelper.cs index 2c6b0c76..a71d8c31 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ResourceHelper.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ResourceHelper.cs @@ -3,99 +3,47 @@ namespace Microsoft.Xaml.Interactivity; -using Windows.ApplicationModel.Resources; - -internal static class ResourceHelper +internal static partial class ResourceHelper { -#if NET8_0_OR_GREATER && !MODERN_WINDOWS_UWP - private static ResourceLoader strings = new ResourceLoader(ResourceLoader.GetDefaultResourceFilePath(), "Microsoft.Xaml.Interactivity/Strings"); -#endif - - public static string GetString(string resourceName) - { -#if !NET8_0_OR_GREATER || MODERN_WINDOWS_UWP - ResourceLoader strings = ResourceLoader.GetForCurrentView("Microsoft.Xaml.Interactivity/Strings"); -#endif - return strings.GetString(resourceName); - } - public static string CallMethodActionValidMethodNotFoundExceptionMessage - { - get - { - return ResourceHelper.GetString("CallMethodActionValidMethodNotFoundExceptionMessage"); - } - } + => Strings.GetString(nameof(CallMethodActionValidMethodNotFoundExceptionMessage)); public static string ChangePropertyActionCannotFindPropertyNameExceptionMessage - { - get - { - return ResourceHelper.GetString("ChangePropertyActionCannotFindPropertyNameExceptionMessage"); - } - } + => Strings.GetString(nameof(ChangePropertyActionCannotFindPropertyNameExceptionMessage)); public static string ChangePropertyActionCannotSetValueExceptionMessage - { - get - { - return ResourceHelper.GetString("ChangePropertyActionCannotSetValueExceptionMessage"); - } - } + => Strings.GetString(nameof(ChangePropertyActionCannotSetValueExceptionMessage)); public static string ChangePropertyActionPropertyIsReadOnlyExceptionMessage - { - get - { - return ResourceHelper.GetString("ChangePropertyActionPropertyIsReadOnlyExceptionMessage"); - } - } + => Strings.GetString(nameof(ChangePropertyActionPropertyIsReadOnlyExceptionMessage)); public static string GoToStateActionTargetHasNoStateGroups - { - get - { - return ResourceHelper.GetString("GoToStateActionTargetHasNoStateGroups"); - } - } + => Strings.GetString(nameof(GoToStateActionTargetHasNoStateGroups)); public static string CannotAttachBehaviorMultipleTimesExceptionMessage - { - get - { - return ResourceHelper.GetString("CannotAttachBehaviorMultipleTimesExceptionMessage"); - } - } + => Strings.GetString(nameof(CannotAttachBehaviorMultipleTimesExceptionMessage)); public static string CannotFindEventNameExceptionMessage - { - get - { - return ResourceHelper.GetString("CannotFindEventNameExceptionMessage"); - } - } + => Strings.GetString(nameof(CannotFindEventNameExceptionMessage)); + + public static string InvalidAssociatedObjectExceptionMessage + => Strings.GetString(nameof(InvalidAssociatedObjectExceptionMessage)); + + public static string NonActionAddedToActionCollectionExceptionMessage + => Strings.GetString(nameof(NonActionAddedToActionCollectionExceptionMessage)); + + public static string NonBehaviorAddedToBehaviorCollectionExceptionMessage + => Strings.GetString(nameof(NonBehaviorAddedToBehaviorCollectionExceptionMessage)); + + public static string DuplicateBehaviorInCollectionExceptionMessage + => Strings.GetString(nameof(DuplicateBehaviorInCollectionExceptionMessage)); public static string InvalidLeftOperand - { - get - { - return ResourceHelper.GetString("InvalidLeftOperand"); - } - } + => Strings.GetString(nameof(InvalidLeftOperand)); public static string InvalidRightOperand - { - get - { - return ResourceHelper.GetString("InvalidRightOperand"); - } - } + => Strings.GetString(nameof(InvalidRightOperand)); public static string InvalidOperands - { - get - { - return ResourceHelper.GetString("InvalidOperands"); - } - } + => Strings.GetString(nameof(InvalidOperands)); } diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/TriggerOfT.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/TriggerOfT.cs index 90c8ea70..3f321bea 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/TriggerOfT.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/TriggerOfT.cs @@ -41,7 +41,7 @@ protected override void OnAttached() { string actualType = base.AssociatedObject.GetType().FullName; string expectedType = typeof(T).FullName; - string message = string.Format(ResourceHelper.GetString("InvalidAssociatedObjectExceptionMessage"), actualType, expectedType); + string message = string.Format(ResourceHelper.InvalidAssociatedObjectExceptionMessage, actualType, expectedType); throw new InvalidOperationException(message); } } diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Uwp/Core/ResourceHelper.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Uwp/Core/ResourceHelper.cs new file mode 100644 index 00000000..864736e3 --- /dev/null +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Uwp/Core/ResourceHelper.cs @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.Xaml.Interactivity; + +using Windows.ApplicationModel.Resources; + +internal static partial class ResourceHelper +{ + private static ResourceLoader Strings => ResourceLoader.GetForCurrentView("Microsoft.Xaml.Interactivity/Strings"); +} \ No newline at end of file diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Uwp/Microsoft.Xaml.Interactivity.Uwp.csproj b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Uwp/Microsoft.Xaml.Interactivity.Uwp.csproj index 4e6720c8..8e93a268 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Uwp/Microsoft.Xaml.Interactivity.Uwp.csproj +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Uwp/Microsoft.Xaml.Interactivity.Uwp.csproj @@ -1,7 +1,6 @@  Library - $(DefineConstants);MODERN_WINDOWS_UWP Microsoft.Xaml.Interactivity net8.0-windows10.0.19041.0 10.0.19041.57 diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.WinUI/Core/ResourceHelper.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.WinUI/Core/ResourceHelper.cs new file mode 100644 index 00000000..fb54f9b7 --- /dev/null +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.WinUI/Core/ResourceHelper.cs @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.Xaml.Interactivity; + +using Windows.ApplicationModel.Resources; + +internal static partial class ResourceHelper +{ + private static ResourceLoader Strings { get; } = new(ResourceLoader.GetDefaultResourceFilePath(), "Microsoft.Xaml.Interactivity/Strings"); +} \ No newline at end of file diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity/Core/ResourceHelper.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity/Core/ResourceHelper.cs new file mode 100644 index 00000000..864736e3 --- /dev/null +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity/Core/ResourceHelper.cs @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.Xaml.Interactivity; + +using Windows.ApplicationModel.Resources; + +internal static partial class ResourceHelper +{ + private static ResourceLoader Strings => ResourceLoader.GetForCurrentView("Microsoft.Xaml.Interactivity/Strings"); +} \ No newline at end of file diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity/Microsoft.Xaml.Interactivity.csproj b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity/Microsoft.Xaml.Interactivity.csproj index 761af2dd..de26b6e2 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity/Microsoft.Xaml.Interactivity.csproj +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity/Microsoft.Xaml.Interactivity.csproj @@ -108,6 +108,7 @@ + From 8574e90c1f63d3c72cd622f75f1c6d601136b187 Mon Sep 17 00:00:00 2001 From: Charles Milette Date: Wed, 4 Jun 2025 20:23:18 -0400 Subject: [PATCH 2/6] CsWinRT and trimming are .NET 5 features --- .../Core/CallMethodAction.cs | 2 +- .../Core/ChangePropertyAction.cs | 2 +- .../Core/DataBindingHelper.cs | 6 +++--- .../Core/DataTriggerBehavior.cs | 2 +- .../Core/EventTriggerBehavior.cs | 19 +++++++++++-------- .../Properties/AssemblyInfo.cs | 2 +- 6 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/CallMethodAction.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/CallMethodAction.cs index 620662b0..83f69d5b 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/CallMethodAction.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/CallMethodAction.cs @@ -19,7 +19,7 @@ namespace Microsoft.Xaml.Interactivity; /// /// An action that calls a method on a specified object when invoked. /// -#if NET8_0_OR_GREATER +#if NET5_0_OR_GREATER [RequiresUnreferencedCode("This action is not trim-safe.")] #endif public sealed class CallMethodAction : DependencyObject, IAction diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ChangePropertyAction.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ChangePropertyAction.cs index 9de5e718..b2fef87b 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ChangePropertyAction.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ChangePropertyAction.cs @@ -17,7 +17,7 @@ namespace Microsoft.Xaml.Interactivity; /// /// An action that will change a specified property to a specified value when invoked. /// -#if NET8_0_OR_GREATER +#if NET5_0_OR_GREATER [RequiresUnreferencedCode("This action is not trim-safe.")] #endif public sealed class ChangePropertyAction : DependencyObject, IAction diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/DataBindingHelper.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/DataBindingHelper.cs index 93dde39a..8a05ce3e 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/DataBindingHelper.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/DataBindingHelper.cs @@ -3,7 +3,7 @@ using System; using System.Collections.Generic; -#if NET8_0_OR_GREATER +#if NET5_0_OR_GREATER using System.Diagnostics.CodeAnalysis; #endif using System.Reflection; @@ -30,7 +30,7 @@ internal static class DataBindingHelper /// bindings on the action may not be up-to-date. This routine is called before the action /// is executed in order to guarantee that all bindings are refreshed with the most current data. /// -#if NET8_0_OR_GREATER +#if NET5_0_OR_GREATER [RequiresUnreferencedCode("This method accesses all fields of input action objects.")] #endif public static void RefreshDataBindingsOnActions(ActionCollection actions) @@ -45,7 +45,7 @@ public static void RefreshDataBindingsOnActions(ActionCollection actions) } private static IEnumerable GetDependencyProperties( -#if NET8_0_OR_GREATER +#if NET5_0_OR_GREATER [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] #endif Type type) diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/DataTriggerBehavior.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/DataTriggerBehavior.cs index 90c2b899..1ddf4c67 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/DataTriggerBehavior.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/DataTriggerBehavior.cs @@ -16,7 +16,7 @@ namespace Microsoft.Xaml.Interactivity; /// /// A behavior that performs actions when the bound data meets a specified condition. /// -#if NET8_0_OR_GREATER +#if NET5_0_OR_GREATER [RequiresUnreferencedCode("This behavior is not trim-safe.")] #endif public sealed class DataTriggerBehavior : Trigger diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/EventTriggerBehavior.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/EventTriggerBehavior.cs index 3850333b..c69cf607 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/EventTriggerBehavior.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/EventTriggerBehavior.cs @@ -2,7 +2,6 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; -using System.Diagnostics.CodeAnalysis; using System.Reflection; #if WinUI @@ -12,7 +11,10 @@ using Windows.UI.Xaml; using Windows.UI.Xaml.Media; #endif -#if WINDOWS_UWP && !NET8_0_OR_GREATER + +#if NET5_0_OR_GREATER +using System.Diagnostics.CodeAnalysis; +#else using System.Runtime.InteropServices.WindowsRuntime; #endif @@ -21,7 +23,7 @@ namespace Microsoft.Xaml.Interactivity; /// /// A behavior that listens for a specified event on its source and executes its actions when that event is fired. /// -#if NET8_0_OR_GREATER +#if NET5_0_OR_GREATER [RequiresUnreferencedCode("This behavior is not trim-safe.")] #endif public sealed class EventTriggerBehavior : Trigger @@ -49,7 +51,7 @@ public sealed class EventTriggerBehavior : Trigger private object _resolvedSource; private Delegate _eventHandler; private bool _isLoadedEventRegistered; -#if !NET8_0_OR_GREATER +#if !NET5_0_OR_GREATER private bool _isWindowsRuntimeEvent; private Func _addEventHandlerMethod; private Action _removeEventHandlerMethod; @@ -164,7 +166,7 @@ private void RegisterEvent(string eventName) MethodInfo methodInfo = typeof(EventTriggerBehavior).GetTypeInfo().GetDeclaredMethod("OnEvent"); this._eventHandler = methodInfo.CreateDelegate(info.EventHandlerType, this); -#if NET8_0_OR_GREATER +#if NET5_0_OR_GREATER info.AddEventHandler(this._resolvedSource, this._eventHandler); #else this._isWindowsRuntimeEvent = EventTriggerBehavior.IsWindowsRuntimeEvent(info); @@ -207,7 +209,7 @@ private void UnregisterEvent(string eventName) } EventInfo info = this._resolvedSource.GetType().GetRuntimeEvent(eventName); -#if NET8_0_OR_GREATER +#if NET5_0_OR_GREATER info.RemoveEventHandler(this._resolvedSource, this._eventHandler); #else if (this._isWindowsRuntimeEvent) @@ -256,7 +258,7 @@ private static void OnEventNameChanged(DependencyObject dependencyObject, Depend behavior.RegisterEvent(newEventName); } -#if !NET8_0_OR_GREATER +#if !NET5_0_OR_GREATER private static bool IsWindowsRuntimeEvent(EventInfo eventInfo) { return eventInfo != null && @@ -269,7 +271,8 @@ private static bool IsWindowsRuntimeType(Type type) if (type != null) { // This will only work when using built-in WinRT interop, ie. where .winmd files are directly - // referenced instead of generated projections. That is, this would not work on modern .NET. + // referenced instead of generated projections. That is, this would not work on .NET 5 or higher, + // where CsWinRT is used instead. return type.AssemblyQualifiedName.EndsWith("ContentType=WindowsRuntime", StringComparison.Ordinal); } diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Properties/AssemblyInfo.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Properties/AssemblyInfo.cs index 8c258ea4..3695bee6 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Properties/AssemblyInfo.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Properties/AssemblyInfo.cs @@ -8,7 +8,7 @@ // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -#if !NET8_0_OR_GREATER +#if !NET5_0_OR_GREATER [assembly: AssemblyTitle("Microsoft.Xaml.Interactivity")] [assembly: AssemblyCompany("Microsoft")] [assembly: AssemblyProduct("Microsoft.Xaml.Interactivity")] From ae4fe4f16f3dbeaa8815e940bf0d34cff6813a49 Mon Sep 17 00:00:00 2001 From: Charles Milette Date: Wed, 4 Jun 2025 20:25:08 -0400 Subject: [PATCH 3/6] New action: ChangeDependencyPropertyAction --- .../Core/ChangeDependencyPropertyAction.cs | 88 +++++++++++++++++++ .../Core/ChangePropertyAction.cs | 5 +- ...rosoft.Xaml.Interactivity.Shared.projitems | 1 + 3 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ChangeDependencyPropertyAction.cs diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ChangeDependencyPropertyAction.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ChangeDependencyPropertyAction.cs new file mode 100644 index 00000000..3852ba76 --- /dev/null +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ChangeDependencyPropertyAction.cs @@ -0,0 +1,88 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#if WinUI +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Markup; +#else +using Windows.UI.Xaml; +using Windows.UI.Xaml.Markup; +#endif + +namespace Microsoft.Xaml.Interactivity; + +/// +/// An action that will change a specified dependency property to a specified value when invoked. +/// +[ContentProperty(Name = "Value")] +public sealed class ChangeDependencyPropertyAction : DependencyObject, IAction +{ + /// + /// Identifies the dependency property. + /// + public static readonly DependencyProperty TargetObjectProperty = DependencyProperty.Register( + "TargetObject", + typeof(DependencyObject), + typeof(ChangeDependencyPropertyAction), + new PropertyMetadata(null)); + + /// + /// Identifies the dependency property. + /// + public static readonly DependencyProperty ValueProperty = DependencyProperty.Register( + "Value", + typeof(object), + typeof(ChangeDependencyPropertyAction), + new PropertyMetadata(null)); + + /// + /// Gets or sets the dependency property to change. This is not a dependency property, due to framework restrictions. + /// + public DependencyProperty DependencyProperty { get; set; } + + /// + /// Gets or sets the value to set. This is a dependency property. + /// + public object Value + { + get => GetValue(ValueProperty); + set => SetValue(ValueProperty, value); + } + + /// + /// Gets or sets the object whose property will be changed. + /// If is not set or cannot be resolved, the sender of will be used. This is a dependency property. + /// + public DependencyObject TargetObject + { + get => (DependencyObject)GetValue(TargetObjectProperty); + set => SetValue(TargetObjectProperty, value); + } + + /// + /// Executes the action. + /// + /// The that is passed to the action by the behavior. Generally this is or a target object. + /// Ignored + /// True if updating the dependency property value succeeds; else false. + public object Execute(object sender, object parameter) + { + DependencyObject targetObject; + if (ReadLocalValue(TargetObjectProperty) != DependencyProperty.UnsetValue) + { + targetObject = TargetObject; + } + else + { + targetObject = sender as DependencyObject; + } + + if (targetObject == null || DependencyProperty == null) + { + return false; + } + + targetObject.SetValue(DependencyProperty, Value); + return true; + } +} \ No newline at end of file diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ChangePropertyAction.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ChangePropertyAction.cs index b2fef87b..0bd7b97f 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ChangePropertyAction.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ChangePropertyAction.cs @@ -8,8 +8,10 @@ #if WinUI using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Markup; #else using Windows.UI.Xaml; +using Windows.UI.Xaml.Markup; #endif namespace Microsoft.Xaml.Interactivity; @@ -18,8 +20,9 @@ namespace Microsoft.Xaml.Interactivity; /// An action that will change a specified property to a specified value when invoked. /// #if NET5_0_OR_GREATER -[RequiresUnreferencedCode("This action is not trim-safe.")] +[RequiresUnreferencedCode("This action is not trim-safe, as it uses reflection to set the property. Use ChangeDependencyPropertyAction for dependency properties, or write your own purpose-specific action.")] #endif +[ContentProperty(Name = "Value")] public sealed class ChangePropertyAction : DependencyObject, IAction { /// diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Microsoft.Xaml.Interactivity.Shared.projitems b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Microsoft.Xaml.Interactivity.Shared.projitems index 6cb6dc74..3886f499 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Microsoft.Xaml.Interactivity.Shared.projitems +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Microsoft.Xaml.Interactivity.Shared.projitems @@ -14,6 +14,7 @@ + From 6570fdef1bf728d4c032947565f7e641033e38a6 Mon Sep 17 00:00:00 2001 From: Charles Milette Date: Wed, 4 Jun 2025 20:29:38 -0400 Subject: [PATCH 4/6] Add new trim-safe EventTriggerBehaviorBase, rewrite EventTriggerBehavior to be based upon trim-safe base, add various common event-based behaviors --- .../Core/CheckedTriggerBehavior.cs | 29 ++ .../Core/EventTriggerBehavior.cs | 255 ++++-------------- .../Core/EventTriggerBehaviorBase.cs | 145 ++++++++++ .../Core/GoToStateAction.cs | 2 +- .../Core/GotFocusTriggerBehavior.cs | 30 +++ ...yboardAcceleratorInvokedTriggerBehavior.cs | 29 ++ .../Core/LoadedTriggerBehavior.cs | 66 +++++ .../Core/LostFocusTriggerBehavior.cs | 29 ++ .../ManipulationCompletedTriggerBehavior.cs | 29 ++ .../ManipulationStartedTriggerBehavior.cs | 29 ++ .../Core/PointerEnteredTriggerBehavior.cs | 29 ++ .../Core/PointerExitedTriggerBehavior.cs | 29 ++ .../Core/TappedTriggerBehavior.cs | 29 ++ .../Core/UnloadedTriggerBehavior.cs | 29 ++ ...rosoft.Xaml.Interactivity.Shared.projitems | 12 + 15 files changed, 570 insertions(+), 201 deletions(-) create mode 100644 src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/CheckedTriggerBehavior.cs create mode 100644 src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/EventTriggerBehaviorBase.cs create mode 100644 src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/GotFocusTriggerBehavior.cs create mode 100644 src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/KeyboardAcceleratorInvokedTriggerBehavior.cs create mode 100644 src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/LoadedTriggerBehavior.cs create mode 100644 src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/LostFocusTriggerBehavior.cs create mode 100644 src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ManipulationCompletedTriggerBehavior.cs create mode 100644 src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ManipulationStartedTriggerBehavior.cs create mode 100644 src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/PointerEnteredTriggerBehavior.cs create mode 100644 src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/PointerExitedTriggerBehavior.cs create mode 100644 src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/TappedTriggerBehavior.cs create mode 100644 src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/UnloadedTriggerBehavior.cs diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/CheckedTriggerBehavior.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/CheckedTriggerBehavior.cs new file mode 100644 index 00000000..93b0af9f --- /dev/null +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/CheckedTriggerBehavior.cs @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#if WinUI +using Microsoft.UI.Xaml.Controls.Primitives; +#else +using Windows.UI.Xaml.Controls.Primitives; +#endif + +namespace Microsoft.Xaml.Interactivity; + +/// +/// A behavior that listens to an and executes its actions when the button is checked. +/// +public class CheckedTriggerBehavior : EventTriggerBehaviorBase +{ + /// + protected override bool RegisterEventCore(ToggleButton source) + { + source.Checked += OnEvent; + return true; + } + + /// + protected override void UnregisterEventCore(ToggleButton source) + { + source.Checked -= OnEvent; + } +} diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/EventTriggerBehavior.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/EventTriggerBehavior.cs index c69cf607..b9da65c6 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/EventTriggerBehavior.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/EventTriggerBehavior.cs @@ -6,10 +6,8 @@ #if WinUI using Microsoft.UI.Xaml; -using Microsoft.UI.Xaml.Media; #else using Windows.UI.Xaml; -using Windows.UI.Xaml.Media; #endif #if NET5_0_OR_GREATER @@ -24,33 +22,21 @@ namespace Microsoft.Xaml.Interactivity; /// A behavior that listens for a specified event on its source and executes its actions when that event is fired. /// #if NET5_0_OR_GREATER -[RequiresUnreferencedCode("This behavior is not trim-safe.")] +[RequiresUnreferencedCode("This behavior is not trim-safe, as it uses reflection to register the event handler. Use the provided event-specific trigger behaviors, or make your own by deriving from EventTriggerBehaviorBase.")] #endif -public sealed class EventTriggerBehavior : Trigger +public sealed class EventTriggerBehavior : EventTriggerBehaviorBase { /// /// Identifies the dependency property. /// - [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] public static readonly DependencyProperty EventNameProperty = DependencyProperty.Register( "EventName", typeof(string), typeof(EventTriggerBehavior), new PropertyMetadata("Loaded", new PropertyChangedCallback(EventTriggerBehavior.OnEventNameChanged))); - /// - /// Identifies the dependency property. - /// - [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] - public static readonly DependencyProperty SourceObjectProperty = DependencyProperty.Register( - "SourceObject", - typeof(object), - typeof(EventTriggerBehavior), - new PropertyMetadata(null, new PropertyChangedCallback(EventTriggerBehavior.OnSourceObjectChanged))); - - private object _resolvedSource; private Delegate _eventHandler; - private bool _isLoadedEventRegistered; + private EventInfo _event; // null if EventName == Loaded #if !NET5_0_OR_GREATER private bool _isWindowsRuntimeEvent; private Func _addEventHandlerMethod; @@ -69,201 +55,103 @@ public EventTriggerBehavior() /// public string EventName { - get - { - return (string)this.GetValue(EventTriggerBehavior.EventNameProperty); - } - - set - { - this.SetValue(EventTriggerBehavior.EventNameProperty, value); - } - } - - /// - /// Gets or sets the source object from which this behavior listens for events. - /// If is not set, the source will default to . This is a dependency property. - /// - public object SourceObject - { - get - { - return (object)this.GetValue(EventTriggerBehavior.SourceObjectProperty); - } - - set - { - this.SetValue(EventTriggerBehavior.SourceObjectProperty, value); - } - } - - /// - /// Called after the behavior is attached to the . - /// - protected override void OnAttached() - { - base.OnAttached(); - this.SetResolvedSource(this.ComputeResolvedSource()); - } - - /// - /// Called when the behavior is being detached from its . - /// - protected override void OnDetaching() - { - base.OnDetaching(); - this.SetResolvedSource(null); + get => (string)GetValue(EventNameProperty); + set => SetValue(EventNameProperty, value); } - private void SetResolvedSource(object newSource) - { - if (this.AssociatedObject == null || this._resolvedSource == newSource) - { - return; - } - - if (this._resolvedSource != null) - { - this.UnregisterEvent(this.EventName); - } - - this._resolvedSource = newSource; - - if (this._resolvedSource != null) - { - this.RegisterEvent(this.EventName); - } - } - - private object ComputeResolvedSource() - { - // If the SourceObject property is set at all, we want to use it. It is possible that it is data - // bound and bindings haven't been evaluated yet. Plus, this makes the API more predictable. - if (this.ReadLocalValue(EventTriggerBehavior.SourceObjectProperty) != DependencyProperty.UnsetValue) - { - return this.SourceObject; - } - - return this.AssociatedObject; - } - - private void RegisterEvent(string eventName) + /// + protected override bool RegisterEventCore(DependencyObject source) { + var eventName = EventName; if (string.IsNullOrEmpty(eventName)) { - return; + return false; } if (eventName != "Loaded") { - Type sourceObjectType = this._resolvedSource.GetType(); - EventInfo info = sourceObjectType.GetRuntimeEvent(eventName); + Type sourceObjectType = source.GetType(); + var info = sourceObjectType.GetRuntimeEvent(eventName); if (info == null) { - return; + return false; } MethodInfo methodInfo = typeof(EventTriggerBehavior).GetTypeInfo().GetDeclaredMethod("OnEvent"); - this._eventHandler = methodInfo.CreateDelegate(info.EventHandlerType, this); + _eventHandler = methodInfo.CreateDelegate(info.EventHandlerType, this); -#if NET5_0_OR_GREATER - info.AddEventHandler(this._resolvedSource, this._eventHandler); -#else - this._isWindowsRuntimeEvent = EventTriggerBehavior.IsWindowsRuntimeEvent(info); - if (this._isWindowsRuntimeEvent) +#if !NET5_0_OR_GREATER + _isWindowsRuntimeEvent = IsWindowsRuntimeEvent(info); + if (_isWindowsRuntimeEvent) { - this._addEventHandlerMethod = add => (EventRegistrationToken)info.AddMethod.Invoke(this._resolvedSource, new object[] { add }); - this._removeEventHandlerMethod = token => info.RemoveMethod.Invoke(this._resolvedSource, new object[] { token }); + _addEventHandlerMethod = add => (EventRegistrationToken)info.AddMethod.Invoke(source, new object[] { add }); + _removeEventHandlerMethod = token => info.RemoveMethod.Invoke(source, new object[] { token }); - WindowsRuntimeMarshal.AddEventHandler(this._addEventHandlerMethod, this._removeEventHandlerMethod, this._eventHandler); - } - else - { - info.AddEventHandler(this._resolvedSource, this._eventHandler); + WindowsRuntimeMarshal.AddEventHandler(_addEventHandlerMethod, _removeEventHandlerMethod, _eventHandler); + + return true; } #endif + + info.AddEventHandler(source, _eventHandler); + _event = info; + + return true; } - else if (!this._isLoadedEventRegistered) + else if (source is FrameworkElement element && !LoadedTriggerBehavior.IsElementLoaded(element)) { - FrameworkElement element = this._resolvedSource as FrameworkElement; - if (element != null && !EventTriggerBehaviorHelpers.IsElementLoaded(element)) - { - this._isLoadedEventRegistered = true; - element.Loaded += this.OnEvent; - } + element.Loaded += OnEvent; + return true; + } + else + { + return false; } } - private void UnregisterEvent(string eventName) + /// + protected override void UnregisterEventCore(DependencyObject source) { - if (string.IsNullOrEmpty(eventName)) + // Don't use the EventName property in this function. By the point this is called, it might have changed. +#if !NET5_0_OR_GREATER + if (_isWindowsRuntimeEvent) { + WindowsRuntimeMarshal.RemoveEventHandler(_removeEventHandlerMethod, _eventHandler); + _isWindowsRuntimeEvent = false; + _addEventHandlerMethod = null; + _removeEventHandlerMethod = null; + _eventHandler = null; + return; } - - if (eventName != "Loaded") - { - if (this._eventHandler == null) - { - return; - } - - EventInfo info = this._resolvedSource.GetType().GetRuntimeEvent(eventName); -#if NET5_0_OR_GREATER - info.RemoveEventHandler(this._resolvedSource, this._eventHandler); -#else - if (this._isWindowsRuntimeEvent) - { - WindowsRuntimeMarshal.RemoveEventHandler(this._removeEventHandlerMethod, this._eventHandler); - } - else - { - info.RemoveEventHandler(this._resolvedSource, this._eventHandler); - } #endif - this._eventHandler = null; + if (_event != null) + { + _event.RemoveEventHandler(source, _eventHandler); + _event = null; + _eventHandler = null; } - else if (this._isLoadedEventRegistered) + else { - this._isLoadedEventRegistered = false; - FrameworkElement element = (FrameworkElement)this._resolvedSource; - element.Loaded -= this.OnEvent; + ((FrameworkElement)source).Loaded -= OnEvent; } } - private void OnEvent(object sender, object eventArgs) - { - Interaction.ExecuteActions(this._resolvedSource, this.Actions, eventArgs); - } - - private static void OnSourceObjectChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args) - { - EventTriggerBehavior behavior = (EventTriggerBehavior)dependencyObject; - behavior.SetResolvedSource(behavior.ComputeResolvedSource()); - } - private static void OnEventNameChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args) { EventTriggerBehavior behavior = (EventTriggerBehavior)dependencyObject; - if (behavior.AssociatedObject == null || behavior._resolvedSource == null) - { - return; - } - - string oldEventName = (string)args.OldValue; - string newEventName = (string)args.NewValue; - behavior.UnregisterEvent(oldEventName); - behavior.RegisterEvent(newEventName); + behavior.UnregisterEvent(); + behavior.RegisterEvent(); } #if !NET5_0_OR_GREATER private static bool IsWindowsRuntimeEvent(EventInfo eventInfo) { return eventInfo != null && - EventTriggerBehavior.IsWindowsRuntimeType(eventInfo.EventHandlerType) && - EventTriggerBehavior.IsWindowsRuntimeType(eventInfo.DeclaringType); + IsWindowsRuntimeType(eventInfo.EventHandlerType) && + IsWindowsRuntimeType(eventInfo.DeclaringType); } private static bool IsWindowsRuntimeType(Type type) @@ -280,36 +168,3 @@ private static bool IsWindowsRuntimeType(Type type) } #endif } - -internal static class EventTriggerBehaviorHelpers -{ - // This method has to be outside of 'EventTriggerBehavior', because it's actually trim-safe. - // We want to allow other callers inside the library use this without getting trim warnings. - public static bool IsElementLoaded(FrameworkElement element) - { - if (element == null) - { - return false; - } - - UIElement rootVisual = default; - if (element.XamlRoot != null) - { - rootVisual = element.XamlRoot.Content; - } - else if (Window.Current != null) - { - rootVisual = Window.Current.Content; - } - - DependencyObject parent = element.Parent; - if (parent == null) - { - // If the element is the child of a ControlTemplate it will have a null parent even when it is loaded. - // To catch that scenario, also check it's parent in the visual tree. - parent = VisualTreeHelper.GetParent(element); - } - - return (parent != null || (rootVisual != null && element == rootVisual)); - } -} diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/EventTriggerBehaviorBase.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/EventTriggerBehaviorBase.cs new file mode 100644 index 00000000..5f6542e8 --- /dev/null +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/EventTriggerBehaviorBase.cs @@ -0,0 +1,145 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.Xaml.Interactivity; + +#if WinUI +using Microsoft.UI.Xaml; +#else +using Windows.UI.Xaml; +#endif + +namespace Microsoft.Xaml.Interactivity; + +/// +/// A base behavior that listens for an event on its source and executes its actions when that event is fired. +/// +public abstract class EventTriggerBehaviorBase : Trigger where T : DependencyObject +{ + /// + /// Identifies the dependency property. + /// + public static readonly DependencyProperty SourceObjectProperty = DependencyProperty.Register( + "SourceObject", + typeof(T), + typeof(EventTriggerBehaviorBase), + new PropertyMetadata(null, new PropertyChangedCallback(OnSourceObjectChanged))); + + private T _resolvedSource; + private bool _isEventRegistered; + + /// + /// Initializes a new instance of the class. + /// + public EventTriggerBehaviorBase() + { + } + + /// + /// Gets or sets the source object from which this behavior listens for events. + /// If is not set, the source will default to . This is a dependency property. + /// + public T SourceObject + { + get => (T)GetValue(SourceObjectProperty); + set => SetValue(SourceObjectProperty, value); + } + + /// + protected override void OnAttached() + { + base.OnAttached(); + SetResolvedSource(ComputeResolvedSource()); + } + + /// + protected override void OnDetaching() + { + base.OnDetaching(); + SetResolvedSource(null); + } + + /// + /// Contains the core logic to register an event handler + /// + /// The object for which to register the event handler + /// true if the event handler got registered, false if it did not + protected abstract bool RegisterEventCore(T source); + + /// + /// Contains the core logic to unregister an event handler + /// + /// The object for which to unregister the event handler + protected abstract void UnregisterEventCore(T source); + + /// + /// The method that should be called when the event is triggered + /// + /// The event's sender + /// The event arguments + protected void OnEvent(object sender, object eventArgs) + { + Interaction.ExecuteActions(_resolvedSource, Actions, eventArgs); + } + + /// + /// Registers the event handler + /// + protected void RegisterEvent() + { + if (!_isEventRegistered) + { + _isEventRegistered = RegisterEventCore(_resolvedSource); + } + } + + /// + /// Unregisters the event handler + /// + protected void UnregisterEvent() + { + if (_isEventRegistered) + { + _isEventRegistered = false; + UnregisterEventCore(_resolvedSource); + } + } + + private void SetResolvedSource(T newSource) + { + if (AssociatedObject == null || _resolvedSource == newSource) + { + return; + } + + if (_resolvedSource != null) + { + UnregisterEvent(); + } + + _resolvedSource = newSource; + + if (_resolvedSource != null) + { + RegisterEvent(); + } + } + + private T ComputeResolvedSource() + { + // If the SourceObject property is set at all, we want to use it. It is possible that it is data + // bound and bindings haven't been evaluated yet. Plus, this makes the API more predictable. + if (ReadLocalValue(SourceObjectProperty) != DependencyProperty.UnsetValue) + { + return SourceObject; + } + + return AssociatedObject; + } + + private static void OnSourceObjectChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args) + { + EventTriggerBehaviorBase behavior = (EventTriggerBehaviorBase)dependencyObject; + behavior.SetResolvedSource(behavior.ComputeResolvedSource()); + } +} diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/GoToStateAction.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/GoToStateAction.cs index f8b1e823..37677723 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/GoToStateAction.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/GoToStateAction.cs @@ -125,7 +125,7 @@ public object Execute(object sender, object parameter) } FrameworkElement element = sender as FrameworkElement; - if (element == null || !EventTriggerBehaviorHelpers.IsElementLoaded(element)) + if (element == null || !LoadedTriggerBehavior.IsElementLoaded(element)) { return false; } diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/GotFocusTriggerBehavior.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/GotFocusTriggerBehavior.cs new file mode 100644 index 00000000..a485b028 --- /dev/null +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/GotFocusTriggerBehavior.cs @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#if WinUI +using Microsoft.UI.Xaml; +#else +using Windows.UI.Xaml; +#endif + +namespace Microsoft.Xaml.Interactivity; + +/// +/// A behavior that listens to an and executes its actions when the UI element gets focus. +/// + +public class GotFocusTriggerBehavior : EventTriggerBehaviorBase +{ + /// + protected override bool RegisterEventCore(UIElement source) + { + source.GotFocus += OnEvent; + return true; + } + + /// + protected override void UnregisterEventCore(UIElement source) + { + source.GotFocus -= OnEvent; + } +} diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/KeyboardAcceleratorInvokedTriggerBehavior.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/KeyboardAcceleratorInvokedTriggerBehavior.cs new file mode 100644 index 00000000..3452aab9 --- /dev/null +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/KeyboardAcceleratorInvokedTriggerBehavior.cs @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#if WinUI +using Microsoft.UI.Xaml.Input; +#else +using Windows.UI.Xaml.Input; +#endif + +namespace Microsoft.Xaml.Interactivity; + +/// +/// A behavior that listens to an and executes its actions when the accelerator is invoked. +/// +public class KeyboardAcceleratorInvokedTriggerBehavior : EventTriggerBehaviorBase +{ + /// + protected override bool RegisterEventCore(KeyboardAccelerator source) + { + source.Invoked += OnEvent; + return true; + } + + /// + protected override void UnregisterEventCore(KeyboardAccelerator source) + { + source.Invoked -= OnEvent; + } +} diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/LoadedTriggerBehavior.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/LoadedTriggerBehavior.cs new file mode 100644 index 00000000..bd106fe5 --- /dev/null +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/LoadedTriggerBehavior.cs @@ -0,0 +1,66 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#if WinUI +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Media; +#else +using Windows.UI.Xaml; +using Windows.UI.Xaml.Media; +#endif + +namespace Microsoft.Xaml.Interactivity; + +/// +/// A behavior that listens to an and executes its actions when the element is loaded. +/// +public class LoadedTriggerBehavior : EventTriggerBehaviorBase +{ + /// + protected override bool RegisterEventCore(FrameworkElement source) + { + if (!IsElementLoaded(source)) + { + source.Loaded += OnEvent; + return true; + } + else + { + return false; + } + } + + /// + protected override void UnregisterEventCore(FrameworkElement source) + { + source.Loaded -= OnEvent; + } + + internal static bool IsElementLoaded(FrameworkElement element) + { + if (element == null) + { + return false; + } + + UIElement rootVisual = default; + if (element.XamlRoot != null) + { + rootVisual = element.XamlRoot.Content; + } + else if (Window.Current != null) + { + rootVisual = Window.Current.Content; + } + + DependencyObject parent = element.Parent; + if (parent == null) + { + // If the element is the child of a ControlTemplate it will have a null parent even when it is loaded. + // To catch that scenario, also check it's parent in the visual tree. + parent = VisualTreeHelper.GetParent(element); + } + + return (parent != null || (rootVisual != null && element == rootVisual)); + } +} diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/LostFocusTriggerBehavior.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/LostFocusTriggerBehavior.cs new file mode 100644 index 00000000..298d6b05 --- /dev/null +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/LostFocusTriggerBehavior.cs @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#if WinUI +using Microsoft.UI.Xaml; +#else +using Windows.UI.Xaml; +#endif + +namespace Microsoft.Xaml.Interactivity; + +/// +/// A behavior that listens to an and executes its actions when the UI element loses focus. +/// +public class LostFocusTriggerBehavior : EventTriggerBehaviorBase +{ + /// + protected override bool RegisterEventCore(UIElement source) + { + source.LostFocus += OnEvent; + return true; + } + + /// + protected override void UnregisterEventCore(UIElement source) + { + source.LostFocus -= OnEvent; + } +} diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ManipulationCompletedTriggerBehavior.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ManipulationCompletedTriggerBehavior.cs new file mode 100644 index 00000000..3984c739 --- /dev/null +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ManipulationCompletedTriggerBehavior.cs @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#if WinUI +using Microsoft.UI.Xaml; +#else +using Windows.UI.Xaml; +#endif + +namespace Microsoft.Xaml.Interactivity; + +/// +/// A behavior that listens to an and executes its actions when the UI element completes manipulation. +/// +public class ManipulationCompletedTriggerBehavior : EventTriggerBehaviorBase +{ + /// + protected override bool RegisterEventCore(UIElement source) + { + source.ManipulationCompleted += OnEvent; + return true; + } + + /// + protected override void UnregisterEventCore(UIElement source) + { + source.ManipulationCompleted -= OnEvent; + } +} diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ManipulationStartedTriggerBehavior.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ManipulationStartedTriggerBehavior.cs new file mode 100644 index 00000000..ff57c540 --- /dev/null +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ManipulationStartedTriggerBehavior.cs @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#if WinUI +using Microsoft.UI.Xaml; +#else +using Windows.UI.Xaml; +#endif + +namespace Microsoft.Xaml.Interactivity; + +/// +/// A behavior that listens to an and executes its actions when the UI element starts manipulation. +/// +public class ManipulationStartedTriggerBehavior : EventTriggerBehaviorBase +{ + /// + protected override bool RegisterEventCore(UIElement source) + { + source.ManipulationStarted += OnEvent; + return true; + } + + /// + protected override void UnregisterEventCore(UIElement source) + { + source.ManipulationStarted -= OnEvent; + } +} diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/PointerEnteredTriggerBehavior.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/PointerEnteredTriggerBehavior.cs new file mode 100644 index 00000000..ce98279d --- /dev/null +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/PointerEnteredTriggerBehavior.cs @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#if WinUI +using Microsoft.UI.Xaml; +#else +using Windows.UI.Xaml; +#endif + +namespace Microsoft.Xaml.Interactivity; + +/// +/// A behavior that listens to an and executes its actions when the pointer enters the UI element. +/// +public class PointerEnteredTriggerBehavior : EventTriggerBehaviorBase +{ + /// + protected override bool RegisterEventCore(UIElement source) + { + source.PointerEntered += OnEvent; + return true; + } + + /// + protected override void UnregisterEventCore(UIElement source) + { + source.PointerEntered -= OnEvent; + } +} diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/PointerExitedTriggerBehavior.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/PointerExitedTriggerBehavior.cs new file mode 100644 index 00000000..e1e51672 --- /dev/null +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/PointerExitedTriggerBehavior.cs @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#if WinUI +using Microsoft.UI.Xaml; +#else +using Windows.UI.Xaml; +#endif + +namespace Microsoft.Xaml.Interactivity; + +/// +/// A behavior that listens to an and executes its actions when the pointer exits the UI element. +/// +public class PointerExitedTriggerBehavior : EventTriggerBehaviorBase +{ + /// + protected override bool RegisterEventCore(UIElement source) + { + source.PointerExited += OnEvent; + return true; + } + + /// + protected override void UnregisterEventCore(UIElement source) + { + source.PointerExited -= OnEvent; + } +} diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/TappedTriggerBehavior.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/TappedTriggerBehavior.cs new file mode 100644 index 00000000..58eefb63 --- /dev/null +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/TappedTriggerBehavior.cs @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#if WinUI +using Microsoft.UI.Xaml; +#else +using Windows.UI.Xaml; +#endif + +namespace Microsoft.Xaml.Interactivity; + +/// +/// A behavior that listens to an and executes its actions when the UI element gets tapped. +/// +public class TappedTriggerBehavior : EventTriggerBehaviorBase +{ + /// + protected override bool RegisterEventCore(UIElement source) + { + source.Tapped += OnEvent; + return true; + } + + /// + protected override void UnregisterEventCore(UIElement source) + { + source.Tapped -= OnEvent; + } +} diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/UnloadedTriggerBehavior.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/UnloadedTriggerBehavior.cs new file mode 100644 index 00000000..3c6e9179 --- /dev/null +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/UnloadedTriggerBehavior.cs @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#if WinUI +using Microsoft.UI.Xaml; +#else +using Windows.UI.Xaml; +#endif + +namespace Microsoft.Xaml.Interactivity; + +/// +/// A behavior that listens to an and executes its actions when the element is unloaded. +/// +public class UnloadedTriggerBehavior : EventTriggerBehaviorBase +{ + /// + protected override bool RegisterEventCore(FrameworkElement source) + { + source.Unloaded += OnEvent; + return true; + } + + /// + protected override void UnregisterEventCore(FrameworkElement source) + { + source.Unloaded -= OnEvent; + } +} diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Microsoft.Xaml.Interactivity.Shared.projitems b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Microsoft.Xaml.Interactivity.Shared.projitems index 3886f499..a192356b 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Microsoft.Xaml.Interactivity.Shared.projitems +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Microsoft.Xaml.Interactivity.Shared.projitems @@ -16,16 +16,28 @@ + + + + + + + + + + + + From 52f678b5f03bec785bc3f13bfd60a195821d1360 Mon Sep 17 00:00:00 2001 From: Charles Milette Date: Wed, 4 Jun 2025 21:00:15 -0400 Subject: [PATCH 5/6] Remove extra newline --- .../Core/GotFocusTriggerBehavior.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/GotFocusTriggerBehavior.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/GotFocusTriggerBehavior.cs index a485b028..2eb5434e 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/GotFocusTriggerBehavior.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/GotFocusTriggerBehavior.cs @@ -12,7 +12,6 @@ namespace Microsoft.Xaml.Interactivity; /// /// A behavior that listens to an and executes its actions when the UI element gets focus. /// - public class GotFocusTriggerBehavior : EventTriggerBehaviorBase { /// From ae4da8af7db744ea67d024fd037dc924beb1645e Mon Sep 17 00:00:00 2001 From: Charles Milette Date: Wed, 4 Jun 2025 22:56:01 -0400 Subject: [PATCH 6/6] seal the classes --- .../Core/CheckedTriggerBehavior.cs | 2 +- .../Core/GotFocusTriggerBehavior.cs | 2 +- .../Core/KeyboardAcceleratorInvokedTriggerBehavior.cs | 2 +- .../Core/LoadedTriggerBehavior.cs | 2 +- .../Core/LostFocusTriggerBehavior.cs | 2 +- .../Core/ManipulationCompletedTriggerBehavior.cs | 2 +- .../Core/ManipulationStartedTriggerBehavior.cs | 2 +- .../Core/PointerEnteredTriggerBehavior.cs | 2 +- .../Core/PointerExitedTriggerBehavior.cs | 2 +- .../Core/TappedTriggerBehavior.cs | 2 +- .../Core/UnloadedTriggerBehavior.cs | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/CheckedTriggerBehavior.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/CheckedTriggerBehavior.cs index 93b0af9f..62e2bd70 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/CheckedTriggerBehavior.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/CheckedTriggerBehavior.cs @@ -12,7 +12,7 @@ namespace Microsoft.Xaml.Interactivity; /// /// A behavior that listens to an and executes its actions when the button is checked. /// -public class CheckedTriggerBehavior : EventTriggerBehaviorBase +public sealed class CheckedTriggerBehavior : EventTriggerBehaviorBase { /// protected override bool RegisterEventCore(ToggleButton source) diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/GotFocusTriggerBehavior.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/GotFocusTriggerBehavior.cs index 2eb5434e..ed690f0d 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/GotFocusTriggerBehavior.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/GotFocusTriggerBehavior.cs @@ -12,7 +12,7 @@ namespace Microsoft.Xaml.Interactivity; /// /// A behavior that listens to an and executes its actions when the UI element gets focus. /// -public class GotFocusTriggerBehavior : EventTriggerBehaviorBase +public sealed class GotFocusTriggerBehavior : EventTriggerBehaviorBase { /// protected override bool RegisterEventCore(UIElement source) diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/KeyboardAcceleratorInvokedTriggerBehavior.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/KeyboardAcceleratorInvokedTriggerBehavior.cs index 3452aab9..b823d330 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/KeyboardAcceleratorInvokedTriggerBehavior.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/KeyboardAcceleratorInvokedTriggerBehavior.cs @@ -12,7 +12,7 @@ namespace Microsoft.Xaml.Interactivity; /// /// A behavior that listens to an and executes its actions when the accelerator is invoked. /// -public class KeyboardAcceleratorInvokedTriggerBehavior : EventTriggerBehaviorBase +public sealed class KeyboardAcceleratorInvokedTriggerBehavior : EventTriggerBehaviorBase { /// protected override bool RegisterEventCore(KeyboardAccelerator source) diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/LoadedTriggerBehavior.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/LoadedTriggerBehavior.cs index bd106fe5..164de9c8 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/LoadedTriggerBehavior.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/LoadedTriggerBehavior.cs @@ -14,7 +14,7 @@ namespace Microsoft.Xaml.Interactivity; /// /// A behavior that listens to an and executes its actions when the element is loaded. /// -public class LoadedTriggerBehavior : EventTriggerBehaviorBase +public sealed class LoadedTriggerBehavior : EventTriggerBehaviorBase { /// protected override bool RegisterEventCore(FrameworkElement source) diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/LostFocusTriggerBehavior.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/LostFocusTriggerBehavior.cs index 298d6b05..07ef905c 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/LostFocusTriggerBehavior.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/LostFocusTriggerBehavior.cs @@ -12,7 +12,7 @@ namespace Microsoft.Xaml.Interactivity; /// /// A behavior that listens to an and executes its actions when the UI element loses focus. /// -public class LostFocusTriggerBehavior : EventTriggerBehaviorBase +public sealed class LostFocusTriggerBehavior : EventTriggerBehaviorBase { /// protected override bool RegisterEventCore(UIElement source) diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ManipulationCompletedTriggerBehavior.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ManipulationCompletedTriggerBehavior.cs index 3984c739..0c4a5252 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ManipulationCompletedTriggerBehavior.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ManipulationCompletedTriggerBehavior.cs @@ -12,7 +12,7 @@ namespace Microsoft.Xaml.Interactivity; /// /// A behavior that listens to an and executes its actions when the UI element completes manipulation. /// -public class ManipulationCompletedTriggerBehavior : EventTriggerBehaviorBase +public sealed class ManipulationCompletedTriggerBehavior : EventTriggerBehaviorBase { /// protected override bool RegisterEventCore(UIElement source) diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ManipulationStartedTriggerBehavior.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ManipulationStartedTriggerBehavior.cs index ff57c540..0772e11b 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ManipulationStartedTriggerBehavior.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ManipulationStartedTriggerBehavior.cs @@ -12,7 +12,7 @@ namespace Microsoft.Xaml.Interactivity; /// /// A behavior that listens to an and executes its actions when the UI element starts manipulation. /// -public class ManipulationStartedTriggerBehavior : EventTriggerBehaviorBase +public sealed class ManipulationStartedTriggerBehavior : EventTriggerBehaviorBase { /// protected override bool RegisterEventCore(UIElement source) diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/PointerEnteredTriggerBehavior.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/PointerEnteredTriggerBehavior.cs index ce98279d..56a22d88 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/PointerEnteredTriggerBehavior.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/PointerEnteredTriggerBehavior.cs @@ -12,7 +12,7 @@ namespace Microsoft.Xaml.Interactivity; /// /// A behavior that listens to an and executes its actions when the pointer enters the UI element. /// -public class PointerEnteredTriggerBehavior : EventTriggerBehaviorBase +public sealed class PointerEnteredTriggerBehavior : EventTriggerBehaviorBase { /// protected override bool RegisterEventCore(UIElement source) diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/PointerExitedTriggerBehavior.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/PointerExitedTriggerBehavior.cs index e1e51672..fa92cf1f 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/PointerExitedTriggerBehavior.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/PointerExitedTriggerBehavior.cs @@ -12,7 +12,7 @@ namespace Microsoft.Xaml.Interactivity; /// /// A behavior that listens to an and executes its actions when the pointer exits the UI element. /// -public class PointerExitedTriggerBehavior : EventTriggerBehaviorBase +public sealed class PointerExitedTriggerBehavior : EventTriggerBehaviorBase { /// protected override bool RegisterEventCore(UIElement source) diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/TappedTriggerBehavior.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/TappedTriggerBehavior.cs index 58eefb63..b9bf0ee5 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/TappedTriggerBehavior.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/TappedTriggerBehavior.cs @@ -12,7 +12,7 @@ namespace Microsoft.Xaml.Interactivity; /// /// A behavior that listens to an and executes its actions when the UI element gets tapped. /// -public class TappedTriggerBehavior : EventTriggerBehaviorBase +public sealed class TappedTriggerBehavior : EventTriggerBehaviorBase { /// protected override bool RegisterEventCore(UIElement source) diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/UnloadedTriggerBehavior.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/UnloadedTriggerBehavior.cs index 3c6e9179..593fd879 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/UnloadedTriggerBehavior.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/UnloadedTriggerBehavior.cs @@ -12,7 +12,7 @@ namespace Microsoft.Xaml.Interactivity; /// /// A behavior that listens to an and executes its actions when the element is unloaded. /// -public class UnloadedTriggerBehavior : EventTriggerBehaviorBase +public sealed class UnloadedTriggerBehavior : EventTriggerBehaviorBase { /// protected override bool RegisterEventCore(FrameworkElement source)