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/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/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 9de5e718..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;
@@ -17,9 +19,10 @@ namespace Microsoft.Xaml.Interactivity;
///
/// An action that will change a specified property to a specified value when invoked.
///
-#if NET8_0_OR_GREATER
-[RequiresUnreferencedCode("This action is not trim-safe.")]
+#if NET5_0_OR_GREATER
+[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/Core/CheckedTriggerBehavior.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/CheckedTriggerBehavior.cs
new file mode 100644
index 00000000..62e2bd70
--- /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 sealed 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/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..b9da65c6 100644
--- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/EventTriggerBehavior.cs
+++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/EventTriggerBehavior.cs
@@ -2,17 +2,17 @@
// 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
using Microsoft.UI.Xaml;
-using Microsoft.UI.Xaml.Media;
#else
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,35 +21,23 @@ 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
-[RequiresUnreferencedCode("This behavior is not trim-safe.")]
+#if NET5_0_OR_GREATER
+[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;
-#if !NET8_0_OR_GREATER
+ private EventInfo _event; // null if EventName == Loaded
+#if !NET5_0_OR_GREATER
private bool _isWindowsRuntimeEvent;
private Func _addEventHandlerMethod;
private Action _removeEventHandlerMethod;
@@ -67,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());
+ get => (string)GetValue(EventNameProperty);
+ set => SetValue(EventNameProperty, value);
}
- ///
- /// Called when the behavior is being detached from its .
- ///
- protected override void OnDetaching()
- {
- base.OnDetaching();
- this.SetResolvedSource(null);
- }
-
- 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 NET8_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 NET8_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 !NET8_0_OR_GREATER
+#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)
@@ -269,7 +159,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);
}
@@ -277,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..ed690f0d
--- /dev/null
+++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/GotFocusTriggerBehavior.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 focus.
+///
+public sealed 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..b823d330
--- /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 sealed 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..164de9c8
--- /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 sealed 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..07ef905c
--- /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 sealed 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..0c4a5252
--- /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 sealed 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..0772e11b
--- /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 sealed 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..56a22d88
--- /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 sealed 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..fa92cf1f
--- /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 sealed 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/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/Core/TappedTriggerBehavior.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/TappedTriggerBehavior.cs
new file mode 100644
index 00000000..b9bf0ee5
--- /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 sealed 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..593fd879
--- /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 sealed 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 6cb6dc74..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
@@ -14,17 +14,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
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")]
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 @@
+