diff --git a/scripts/Microsoft.Xaml.Behaviors.Uwp.Managed.nuspec b/scripts/Microsoft.Xaml.Behaviors.Uwp.Managed.nuspec index 5321a36..4ba6253 100644 --- a/scripts/Microsoft.Xaml.Behaviors.Uwp.Managed.nuspec +++ b/scripts/Microsoft.Xaml.Behaviors.Uwp.Managed.nuspec @@ -47,10 +47,6 @@ - - - - \ No newline at end of file diff --git a/scripts/Microsoft.Xaml.Behaviors.WinUI.Managed.nuspec b/scripts/Microsoft.Xaml.Behaviors.WinUI.Managed.nuspec index 5a6a6ae..e077d14 100644 --- a/scripts/Microsoft.Xaml.Behaviors.WinUI.Managed.nuspec +++ b/scripts/Microsoft.Xaml.Behaviors.WinUI.Managed.nuspec @@ -34,14 +34,6 @@ - - - - - - \ No newline at end of file diff --git a/src/BehaviorsSDKManaged/Directory.Build.props b/src/BehaviorsSDKManaged/Directory.Build.props new file mode 100644 index 0000000..aca29dc --- /dev/null +++ b/src/BehaviorsSDKManaged/Directory.Build.props @@ -0,0 +1,37 @@ + + + + + $([MSBuild]::EnsureTrailingSlash($([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), BehaviorsSDKManaged.sln)))) + $(BehaviorsSDKManagedSolutionPath) + + + + + 12.0 + true + + + strict + + + true + + diff --git a/src/BehaviorsSDKManaged/ManagedUnitTests/ActionCollectionTest.cs b/src/BehaviorsSDKManaged/ManagedUnitTests/ActionCollectionTest.cs index 978c9eb..f6b3136 100644 --- a/src/BehaviorsSDKManaged/ManagedUnitTests/ActionCollectionTest.cs +++ b/src/BehaviorsSDKManaged/ManagedUnitTests/ActionCollectionTest.cs @@ -5,45 +5,44 @@ using Microsoft.VisualStudio.TestTools.UnitTesting.AppContainer; using Microsoft.Xaml.Interactivity; -namespace ManagedUnitTests +namespace ManagedUnitTests; + +[TestClass] +public class ActionCollectionTest { - [TestClass] - public class ActionCollectionTest + [UITestMethod] + public void Constructor_DefaultConstructor_SetsVolumeCorrectly() + { + PlaySoundAction playSoundAction = new PlaySoundAction(); + Assert.AreEqual(0.5, playSoundAction.Volume, "Volume should be initialized to 0.5"); + } + + [UITestMethod] + public void Invoke_RelativeSource_Invokes() { - [UITestMethod] - public void Constructor_DefaultConstructor_SetsVolumeCorrectly() - { - PlaySoundAction playSoundAction = new PlaySoundAction(); - Assert.AreEqual(0.5, playSoundAction.Volume, "Volume should be initialized to 0.5"); - } - - [UITestMethod] - public void Invoke_RelativeSource_Invokes() - { - PlaySoundAction playSoundAction = new PlaySoundAction(); - - playSoundAction.Source = "foo.wav"; - bool result = (bool)playSoundAction.Execute(null, null); - Assert.IsTrue(result); - } - - [UITestMethod] - public void Invoke_AbsoluteSource_Invokes() - { - PlaySoundAction playSoundAction = new PlaySoundAction(); - - playSoundAction.Source = "ms-appx:///foo.wav"; - bool result = (bool)playSoundAction.Execute(null, null); - Assert.IsTrue(result); - } - - [UITestMethod] - public void Invoke_InvalidSource_ReturnsFalse() - { - PlaySoundAction playSoundAction = new PlaySoundAction(); - - Assert.IsFalse((bool)playSoundAction.Execute(null, null), - "PlaySoundAction.Execute should return false with a null source path."); - } + PlaySoundAction playSoundAction = new PlaySoundAction(); + + playSoundAction.Source = "foo.wav"; + bool result = (bool)playSoundAction.Execute(null, null); + Assert.IsTrue(result); + } + + [UITestMethod] + public void Invoke_AbsoluteSource_Invokes() + { + PlaySoundAction playSoundAction = new PlaySoundAction(); + + playSoundAction.Source = "ms-appx:///foo.wav"; + bool result = (bool)playSoundAction.Execute(null, null); + Assert.IsTrue(result); + } + + [UITestMethod] + public void Invoke_InvalidSource_ReturnsFalse() + { + PlaySoundAction playSoundAction = new PlaySoundAction(); + + Assert.IsFalse((bool)playSoundAction.Execute(null, null), + "PlaySoundAction.Execute should return false with a null source path."); } } diff --git a/src/BehaviorsSDKManaged/ManagedUnitTests/BehaviorCollectionTest.cs b/src/BehaviorsSDKManaged/ManagedUnitTests/BehaviorCollectionTest.cs index ee0d254..6c4466c 100644 --- a/src/BehaviorsSDKManaged/ManagedUnitTests/BehaviorCollectionTest.cs +++ b/src/BehaviorsSDKManaged/ManagedUnitTests/BehaviorCollectionTest.cs @@ -6,246 +6,245 @@ using Microsoft.Xaml.Interactivity; using Windows.UI.Xaml.Controls; -namespace ManagedUnitTests +namespace ManagedUnitTests; + +[TestClass] +public class BehaviorCollectionTest { - [TestClass] - public class BehaviorCollectionTest + [UITestMethod] + public void VectorChanged_NonBehaviorAdded_ExceptionThrown() { - [UITestMethod] - public void VectorChanged_NonBehaviorAdded_ExceptionThrown() - { - BehaviorCollection behaviorCollection = new BehaviorCollection(); - behaviorCollection.Add(new StubBehavior()); + BehaviorCollection behaviorCollection = new BehaviorCollection(); + behaviorCollection.Add(new StubBehavior()); - TestUtilities.AssertThrowsInvalidOperationException(() => behaviorCollection.Add(new TextBlock())); - } + TestUtilities.AssertThrowsInvalidOperationException(() => behaviorCollection.Add(new TextBlock())); + } - [UITestMethod] - public void VectorChanged_BehaviorChangedToNonBehavior_ExceptionThrown() - { - BehaviorCollection behaviorCollection = new BehaviorCollection(); - behaviorCollection.Add(new StubBehavior()); + [UITestMethod] + public void VectorChanged_BehaviorChangedToNonBehavior_ExceptionThrown() + { + BehaviorCollection behaviorCollection = new BehaviorCollection(); + behaviorCollection.Add(new StubBehavior()); - TestUtilities.AssertThrowsInvalidOperationException(() => behaviorCollection[0] = new ToggleSwitch()); - } + TestUtilities.AssertThrowsInvalidOperationException(() => behaviorCollection[0] = new ToggleSwitch()); + } - [UITestMethod] - public void VectorChanged_DuplicateAdd_ExceptionThrown() - { - BehaviorCollection behaviorCollection = new BehaviorCollection(); - StubBehavior stub = new StubBehavior(); - behaviorCollection.Add(stub); + [UITestMethod] + public void VectorChanged_DuplicateAdd_ExceptionThrown() + { + BehaviorCollection behaviorCollection = new BehaviorCollection(); + StubBehavior stub = new StubBehavior(); + behaviorCollection.Add(stub); - TestUtilities.AssertThrowsInvalidOperationException(() => behaviorCollection.Add(stub)); + TestUtilities.AssertThrowsInvalidOperationException(() => behaviorCollection.Add(stub)); - } + } - [UITestMethod] - public void VectorChanged_AddWhileNotAttached_AttachNotCalled() - { - BehaviorCollection behaviorCollection = new BehaviorCollection(); - StubBehavior stub = new StubBehavior(); - behaviorCollection.Add(stub); + [UITestMethod] + public void VectorChanged_AddWhileNotAttached_AttachNotCalled() + { + BehaviorCollection behaviorCollection = new BehaviorCollection(); + StubBehavior stub = new StubBehavior(); + behaviorCollection.Add(stub); - TestUtilities.AssertNotAttached(stub); - } + TestUtilities.AssertNotAttached(stub); + } - [UITestMethod] - public void VectorChanged_AddWhileAttached_AllAttached() - { - BehaviorCollection behaviorCollection = new BehaviorCollection(); - behaviorCollection.Attach(new Button()); + [UITestMethod] + public void VectorChanged_AddWhileAttached_AllAttached() + { + BehaviorCollection behaviorCollection = new BehaviorCollection(); + behaviorCollection.Attach(new Button()); - behaviorCollection.Add(new StubBehavior()); - behaviorCollection.Add(new StubBehavior()); - behaviorCollection.Add(new StubBehavior()); + behaviorCollection.Add(new StubBehavior()); + behaviorCollection.Add(new StubBehavior()); + behaviorCollection.Add(new StubBehavior()); - foreach (StubBehavior stub in behaviorCollection) - { - TestUtilities.AssertAttached(stub, behaviorCollection.AssociatedObject); - } + foreach (StubBehavior stub in behaviorCollection) + { + TestUtilities.AssertAttached(stub, behaviorCollection.AssociatedObject); } + } - [UITestMethod] - public void VectorChanged_ReplaceWhileAttached_OldDetachedNewAttached() - { - BehaviorCollection behaviorCollection = new BehaviorCollection(); - behaviorCollection.Attach(new Button()); + [UITestMethod] + public void VectorChanged_ReplaceWhileAttached_OldDetachedNewAttached() + { + BehaviorCollection behaviorCollection = new BehaviorCollection(); + behaviorCollection.Attach(new Button()); - StubBehavior first = new StubBehavior(); - behaviorCollection.Add(first); + StubBehavior first = new StubBehavior(); + behaviorCollection.Add(first); - StubBehavior second = new StubBehavior(); + StubBehavior second = new StubBehavior(); - behaviorCollection[0] = second; + behaviorCollection[0] = second; - TestUtilities.AssertDetached(first); + TestUtilities.AssertDetached(first); - TestUtilities.AssertAttached(second, behaviorCollection.AssociatedObject); - } + TestUtilities.AssertAttached(second, behaviorCollection.AssociatedObject); + } - [UITestMethod] - public void VectorChanged_RemoveWhileNotAttached_DetachNotCalled() - { - BehaviorCollection behaviorCollection = new BehaviorCollection(); + [UITestMethod] + public void VectorChanged_RemoveWhileNotAttached_DetachNotCalled() + { + BehaviorCollection behaviorCollection = new BehaviorCollection(); - StubBehavior behavior = new StubBehavior(); - behaviorCollection.Add(behavior); - behaviorCollection.Remove(behavior); + StubBehavior behavior = new StubBehavior(); + behaviorCollection.Add(behavior); + behaviorCollection.Remove(behavior); - TestUtilities.AssertNotDetached(behavior); - } + TestUtilities.AssertNotDetached(behavior); + } - [UITestMethod] - public void VectorChanged_RemoveWhileAttached_Detached() - { - BehaviorCollection behaviorCollection = new BehaviorCollection(); - behaviorCollection.Attach(new ToggleSwitch()); + [UITestMethod] + public void VectorChanged_RemoveWhileAttached_Detached() + { + BehaviorCollection behaviorCollection = new BehaviorCollection(); + behaviorCollection.Attach(new ToggleSwitch()); - StubBehavior behavior = new StubBehavior(); - behaviorCollection.Add(behavior); - behaviorCollection.Remove(behavior); + StubBehavior behavior = new StubBehavior(); + behaviorCollection.Add(behavior); + behaviorCollection.Remove(behavior); - TestUtilities.AssertDetached(behavior); - } + TestUtilities.AssertDetached(behavior); + } - [UITestMethod] - public void VectorChanged_ResetWhileNotAttached_DetachNotCalled() - { - StubBehavior[] behaviorArray = { new StubBehavior(), new StubBehavior(), new StubBehavior() }; + [UITestMethod] + public void VectorChanged_ResetWhileNotAttached_DetachNotCalled() + { + StubBehavior[] behaviorArray = { new StubBehavior(), new StubBehavior(), new StubBehavior() }; - BehaviorCollection behaviorCollection = new BehaviorCollection(); - foreach (StubBehavior behavior in behaviorArray) - { - behaviorCollection.Add(behavior); - } + BehaviorCollection behaviorCollection = new BehaviorCollection(); + foreach (StubBehavior behavior in behaviorArray) + { + behaviorCollection.Add(behavior); + } - behaviorCollection.Clear(); + behaviorCollection.Clear(); - foreach (StubBehavior behavior in behaviorArray) - { - TestUtilities.AssertNotDetached(behavior); - } + foreach (StubBehavior behavior in behaviorArray) + { + TestUtilities.AssertNotDetached(behavior); } + } - [UITestMethod] - public void VectorChanged_ResetWhileAttached_AllDetached() - { - StubBehavior[] behaviorArray = { new StubBehavior(), new StubBehavior(), new StubBehavior() }; + [UITestMethod] + public void VectorChanged_ResetWhileAttached_AllDetached() + { + StubBehavior[] behaviorArray = { new StubBehavior(), new StubBehavior(), new StubBehavior() }; - BehaviorCollection behaviorCollection = new BehaviorCollection(); - behaviorCollection.Attach(new Button()); + BehaviorCollection behaviorCollection = new BehaviorCollection(); + behaviorCollection.Attach(new Button()); - foreach (StubBehavior behavior in behaviorArray) - { - behaviorCollection.Add(behavior); - } + foreach (StubBehavior behavior in behaviorArray) + { + behaviorCollection.Add(behavior); + } - behaviorCollection.Clear(); + behaviorCollection.Clear(); - foreach (StubBehavior behavior in behaviorArray) - { - TestUtilities.AssertDetached(behavior); - } + foreach (StubBehavior behavior in behaviorArray) + { + TestUtilities.AssertDetached(behavior); } + } - [UITestMethod] - public void Attach_MultipleBehaviors_AllAttached() - { - BehaviorCollection behaviorCollection = new BehaviorCollection(); - behaviorCollection.Add(new StubBehavior()); - behaviorCollection.Add(new StubBehavior()); - behaviorCollection.Add(new StubBehavior()); + [UITestMethod] + public void Attach_MultipleBehaviors_AllAttached() + { + BehaviorCollection behaviorCollection = new BehaviorCollection(); + behaviorCollection.Add(new StubBehavior()); + behaviorCollection.Add(new StubBehavior()); + behaviorCollection.Add(new StubBehavior()); - Button button = new Button(); - behaviorCollection.Attach(button); + Button button = new Button(); + behaviorCollection.Attach(button); - Assert.AreEqual(button, behaviorCollection.AssociatedObject, "Attach should set the AssociatedObject to the given parameter."); + Assert.AreEqual(button, behaviorCollection.AssociatedObject, "Attach should set the AssociatedObject to the given parameter."); - foreach (StubBehavior stub in behaviorCollection) - { - TestUtilities.AssertAttached(stub, button); - } + foreach (StubBehavior stub in behaviorCollection) + { + TestUtilities.AssertAttached(stub, button); } + } - [UITestMethod] - public void Attach_Null_AttachNotCalledOnItems() - { - BehaviorCollection behaviorCollection = new BehaviorCollection(); - behaviorCollection.Add(new StubBehavior()); - behaviorCollection.Add(new StubBehavior()); - behaviorCollection.Add(new StubBehavior()); + [UITestMethod] + public void Attach_Null_AttachNotCalledOnItems() + { + BehaviorCollection behaviorCollection = new BehaviorCollection(); + behaviorCollection.Add(new StubBehavior()); + behaviorCollection.Add(new StubBehavior()); + behaviorCollection.Add(new StubBehavior()); - behaviorCollection.Attach(null); + behaviorCollection.Attach(null); - foreach (StubBehavior stub in behaviorCollection) - { - TestUtilities.AssertNotAttached(stub); - } + foreach (StubBehavior stub in behaviorCollection) + { + TestUtilities.AssertNotAttached(stub); } + } - [UITestMethod] - public void Attach_MultipleObjects_ExceptionThrown() - { - BehaviorCollection behaviorCollection = new BehaviorCollection(); - StubBehavior stub = new StubBehavior(); - behaviorCollection.Attach(new Button()); + [UITestMethod] + public void Attach_MultipleObjects_ExceptionThrown() + { + BehaviorCollection behaviorCollection = new BehaviorCollection(); + StubBehavior stub = new StubBehavior(); + behaviorCollection.Attach(new Button()); - TestUtilities.AssertThrowsInvalidOperationException(() => behaviorCollection.Attach(new StackPanel())); - } + TestUtilities.AssertThrowsInvalidOperationException(() => behaviorCollection.Attach(new StackPanel())); + } - [UITestMethod] - public void Attach_NonNullThenNull_ExceptionThrown() - { - BehaviorCollection behaviorCollection = new BehaviorCollection(); - behaviorCollection.Add(new StubBehavior()); + [UITestMethod] + public void Attach_NonNullThenNull_ExceptionThrown() + { + BehaviorCollection behaviorCollection = new BehaviorCollection(); + behaviorCollection.Add(new StubBehavior()); - behaviorCollection.Attach(new Button()); + behaviorCollection.Attach(new Button()); - TestUtilities.AssertThrowsInvalidOperationException(() => behaviorCollection.Attach(null)); - } + TestUtilities.AssertThrowsInvalidOperationException(() => behaviorCollection.Attach(null)); + } - [UITestMethod] - public void Attach_MultipleTimeSameObject_AttachCalledOnce() - { - BehaviorCollection behaviorCollection = new BehaviorCollection() { new StubBehavior() }; + [UITestMethod] + public void Attach_MultipleTimeSameObject_AttachCalledOnce() + { + BehaviorCollection behaviorCollection = new BehaviorCollection() { new StubBehavior() }; - Button button = new Button(); - behaviorCollection.Attach(button); - behaviorCollection.Attach(button); + Button button = new Button(); + behaviorCollection.Attach(button); + behaviorCollection.Attach(button); - // This method hard codes AttachCount == 1. - TestUtilities.AssertAttached((StubBehavior)behaviorCollection[0], button); - } + // This method hard codes AttachCount == 1. + TestUtilities.AssertAttached((StubBehavior)behaviorCollection[0], button); + } - [UITestMethod] - public void Detach_NotAttached_DetachNotCalledOnItems() - { - BehaviorCollection behaviorCollection = new BehaviorCollection() { new StubBehavior() }; + [UITestMethod] + public void Detach_NotAttached_DetachNotCalledOnItems() + { + BehaviorCollection behaviorCollection = new BehaviorCollection() { new StubBehavior() }; - behaviorCollection.Detach(); + behaviorCollection.Detach(); - TestUtilities.AssertNotDetached((StubBehavior)behaviorCollection[0]); - } + TestUtilities.AssertNotDetached((StubBehavior)behaviorCollection[0]); + } - [UITestMethod] - public void Detach_Attached_AllItemsDetached() - { - BehaviorCollection behaviorCollection = new BehaviorCollection(); - behaviorCollection.Add(new StubBehavior()); - behaviorCollection.Add(new StubBehavior()); - behaviorCollection.Add(new StubBehavior()); + [UITestMethod] + public void Detach_Attached_AllItemsDetached() + { + BehaviorCollection behaviorCollection = new BehaviorCollection(); + behaviorCollection.Add(new StubBehavior()); + behaviorCollection.Add(new StubBehavior()); + behaviorCollection.Add(new StubBehavior()); - behaviorCollection.Attach(new Button()); - behaviorCollection.Detach(); + behaviorCollection.Attach(new Button()); + behaviorCollection.Detach(); - Assert.IsNull(behaviorCollection.AssociatedObject, "The AssociatedObject should be null after Detach."); + Assert.IsNull(behaviorCollection.AssociatedObject, "The AssociatedObject should be null after Detach."); - foreach (StubBehavior behavior in behaviorCollection) - { - TestUtilities.AssertDetached(behavior); - } + foreach (StubBehavior behavior in behaviorCollection) + { + TestUtilities.AssertDetached(behavior); } } } diff --git a/src/BehaviorsSDKManaged/ManagedUnitTests/BlankPage.xaml.cs b/src/BehaviorsSDKManaged/ManagedUnitTests/BlankPage.xaml.cs index 27f017d..ba99bec 100644 --- a/src/BehaviorsSDKManaged/ManagedUnitTests/BlankPage.xaml.cs +++ b/src/BehaviorsSDKManaged/ManagedUnitTests/BlankPage.xaml.cs @@ -1,21 +1,20 @@ using Windows.UI.Xaml.Controls; -namespace ManagedUnitTests +namespace ManagedUnitTests; + +/// +/// This page serves two purposes: +/// +/// 1. Its existence causes the XAML compiler to implement IXamlMetadataProvider +/// on the App class. IXamlMetadataProvider is used by NavigateToPageAction and will +/// only be implemented on App if there are XAML types defined in the project. +/// +/// 2. It provides a target for the NavigateToPageAction to navigate to in tests. +/// +public sealed partial class BlankPage : Page { - /// - /// This page serves two purposes: - /// - /// 1. Its existence causes the XAML compiler to implement IXamlMetadataProvider - /// on the App class. IXamlMetadataProvider is used by NavigateToPageAction and will - /// only be implemented on App if there are XAML types defined in the project. - /// - /// 2. It provides a target for the NavigateToPageAction to navigate to in tests. - /// - public sealed partial class BlankPage : Page + public BlankPage() { - public BlankPage() - { - this.InitializeComponent(); - } + this.InitializeComponent(); } } diff --git a/src/BehaviorsSDKManaged/ManagedUnitTests/InteractionTest.cs b/src/BehaviorsSDKManaged/ManagedUnitTests/InteractionTest.cs index b43b569..70cfa75 100644 --- a/src/BehaviorsSDKManaged/ManagedUnitTests/InteractionTest.cs +++ b/src/BehaviorsSDKManaged/ManagedUnitTests/InteractionTest.cs @@ -9,149 +9,148 @@ using Microsoft.Xaml.Interactivity; using Windows.UI.Xaml.Controls; -namespace ManagedUnitTests +namespace ManagedUnitTests; + +[TestClass] +public class InteractionTest { - [TestClass] - public class InteractionTest + [UITestMethod] + public void SetBehaviors_MultipleBehaviors_AllAttached() { - [UITestMethod] - public void SetBehaviors_MultipleBehaviors_AllAttached() + BehaviorCollection behaviorCollection = new BehaviorCollection(); + behaviorCollection.Add(new StubBehavior()); + behaviorCollection.Add(new StubBehavior()); + behaviorCollection.Add(new StubBehavior()); + + Button button = new Button(); + Interaction.SetBehaviors(button, behaviorCollection); + + foreach (StubBehavior behavior in behaviorCollection) { - BehaviorCollection behaviorCollection = new BehaviorCollection(); - behaviorCollection.Add(new StubBehavior()); - behaviorCollection.Add(new StubBehavior()); - behaviorCollection.Add(new StubBehavior()); - - Button button = new Button(); - Interaction.SetBehaviors(button, behaviorCollection); - - foreach (StubBehavior behavior in behaviorCollection) - { - Assert.AreEqual(1, behavior.AttachCount, "Should only have called Attach once."); - Assert.AreEqual(0, behavior.DetachCount, "Should not have called Detach."); - Assert.AreEqual(button, behavior.AssociatedObject, "Should be attached to the host of the BehaviorCollection."); - } + Assert.AreEqual(1, behavior.AttachCount, "Should only have called Attach once."); + Assert.AreEqual(0, behavior.DetachCount, "Should not have called Detach."); + Assert.AreEqual(button, behavior.AssociatedObject, "Should be attached to the host of the BehaviorCollection."); } + } - [UITestMethod] - public void SetBehaviors_MultipleSets_DoesNotReattach() - { - BehaviorCollection behaviorCollection = new BehaviorCollection() { new StubBehavior() }; + [UITestMethod] + public void SetBehaviors_MultipleSets_DoesNotReattach() + { + BehaviorCollection behaviorCollection = new BehaviorCollection() { new StubBehavior() }; - Button button = new Button(); - Interaction.SetBehaviors(button, behaviorCollection); - Interaction.SetBehaviors(button, behaviorCollection); + Button button = new Button(); + Interaction.SetBehaviors(button, behaviorCollection); + Interaction.SetBehaviors(button, behaviorCollection); - foreach (StubBehavior behavior in behaviorCollection) - { - Assert.AreEqual(1, behavior.AttachCount, "Should only have called Attach once."); - } + foreach (StubBehavior behavior in behaviorCollection) + { + Assert.AreEqual(1, behavior.AttachCount, "Should only have called Attach once."); } + } - [UITestMethod] - public void SetBehaviors_CollectionThenNull_DeatchCollection() - { - BehaviorCollection behaviorCollection = new BehaviorCollection() { new StubBehavior() }; + [UITestMethod] + public void SetBehaviors_CollectionThenNull_DeatchCollection() + { + BehaviorCollection behaviorCollection = new BehaviorCollection() { new StubBehavior() }; - Button button = new Button(); - Interaction.SetBehaviors(button, behaviorCollection); - Interaction.SetBehaviors(button, null); + Button button = new Button(); + Interaction.SetBehaviors(button, behaviorCollection); + Interaction.SetBehaviors(button, null); - foreach (StubBehavior behavior in behaviorCollection) - { - Assert.AreEqual(1, behavior.DetachCount, "Should only have called Detach once."); - Assert.IsNull(behavior.AssociatedObject, "AssociatedObject should be null after Detach."); - } + foreach (StubBehavior behavior in behaviorCollection) + { + Assert.AreEqual(1, behavior.DetachCount, "Should only have called Detach once."); + Assert.IsNull(behavior.AssociatedObject, "AssociatedObject should be null after Detach."); } + } - [UITestMethod] - public void SetBehaviors_NullThenNull_NoOp() - { - // As long as this doesn't crash/assert, we're good. + [UITestMethod] + public void SetBehaviors_NullThenNull_NoOp() + { + // As long as this doesn't crash/assert, we're good. - Button button = new Button(); - Interaction.SetBehaviors(button, null); - Interaction.SetBehaviors(button, null); - Interaction.SetBehaviors(button, null); - } + Button button = new Button(); + Interaction.SetBehaviors(button, null); + Interaction.SetBehaviors(button, null); + Interaction.SetBehaviors(button, null); + } + + [UITestMethod] + + public void SetBehaviors_ManualDetachThenNull_DoesNotDoubleDetach() + { + BehaviorCollection behaviorCollection = new BehaviorCollection(); + behaviorCollection.Add(new StubBehavior()); + behaviorCollection.Add(new StubBehavior()); + behaviorCollection.Add(new StubBehavior()); - [UITestMethod] + Button button = new Button(); + Interaction.SetBehaviors(button, behaviorCollection); - public void SetBehaviors_ManualDetachThenNull_DoesNotDoubleDetach() + foreach (StubBehavior behavior in behaviorCollection) { - BehaviorCollection behaviorCollection = new BehaviorCollection(); - behaviorCollection.Add(new StubBehavior()); - behaviorCollection.Add(new StubBehavior()); - behaviorCollection.Add(new StubBehavior()); - - Button button = new Button(); - Interaction.SetBehaviors(button, behaviorCollection); - - foreach (StubBehavior behavior in behaviorCollection) - { - behavior.Detach(); - } - - Interaction.SetBehaviors(button, null); - - foreach (StubBehavior behavior in behaviorCollection) - { - Assert.AreEqual(1, behavior.DetachCount, "Setting BehaviorCollection to null should not call Detach on already Detached Behaviors."); - Assert.IsNull(behavior.AssociatedObject, "AssociatedObject should be null after Detach."); - } + behavior.Detach(); } - [UITestMethod] - public void ExecuteActions_NullParameters_ReturnsEmptyEnumerable() - { - // Mostly just want to test that this doesn't throw any exceptions. - IEnumerable result = Interaction.ExecuteActions(null, null, null); + Interaction.SetBehaviors(button, null); - Assert.IsNotNull(result); - Assert.AreEqual(0, result.Count(), "Calling ExecuteActions with a null ActionCollection should return an empty enumerable."); + foreach (StubBehavior behavior in behaviorCollection) + { + Assert.AreEqual(1, behavior.DetachCount, "Setting BehaviorCollection to null should not call Detach on already Detached Behaviors."); + Assert.IsNull(behavior.AssociatedObject, "AssociatedObject should be null after Detach."); } + } + + [UITestMethod] + public void ExecuteActions_NullParameters_ReturnsEmptyEnumerable() + { + // Mostly just want to test that this doesn't throw any exceptions. + IEnumerable result = Interaction.ExecuteActions(null, null, null); + + Assert.IsNotNull(result); + Assert.AreEqual(0, result.Count(), "Calling ExecuteActions with a null ActionCollection should return an empty enumerable."); + } + + [UITestMethod] + public void ExecuteActions_MultipleActions_AllActionsExecuted() + { + ActionCollection actions = new ActionCollection(); + actions.Add(new StubAction()); + actions.Add(new StubAction()); + actions.Add(new StubAction()); + + Button sender = new Button(); + string parameterString = "TestString"; + + Interaction.ExecuteActions(sender, actions, parameterString); - [UITestMethod] - public void ExecuteActions_MultipleActions_AllActionsExecuted() + foreach (StubAction action in actions) { - ActionCollection actions = new ActionCollection(); - actions.Add(new StubAction()); - actions.Add(new StubAction()); - actions.Add(new StubAction()); - - Button sender = new Button(); - string parameterString = "TestString"; - - Interaction.ExecuteActions(sender, actions, parameterString); - - foreach (StubAction action in actions) - { - Assert.AreEqual(1, action.ExecuteCount, "Each IAction should be executed once."); - Assert.AreEqual(sender, action.Sender, "Sender is passed to the actions."); - Assert.AreEqual(parameterString, action.Parameter, "Parameter is passed to the actions."); - } + Assert.AreEqual(1, action.ExecuteCount, "Each IAction should be executed once."); + Assert.AreEqual(sender, action.Sender, "Sender is passed to the actions."); + Assert.AreEqual(parameterString, action.Parameter, "Parameter is passed to the actions."); } + } - [UITestMethod] - public void ExecuteActions_ActionsWithResults_ResultsInActionOrder() - { - string[] expectedReturnValues = { "A", "B", "C" }; + [UITestMethod] + public void ExecuteActions_ActionsWithResults_ResultsInActionOrder() + { + string[] expectedReturnValues = { "A", "B", "C" }; - ActionCollection actions = new ActionCollection(); + ActionCollection actions = new ActionCollection(); - foreach (string returnValue in expectedReturnValues) - { - actions.Add(new StubAction(returnValue)); - } + foreach (string returnValue in expectedReturnValues) + { + actions.Add(new StubAction(returnValue)); + } - List results = Interaction.ExecuteActions(null, actions, null).ToList(); + List results = Interaction.ExecuteActions(null, actions, null).ToList(); - Assert.AreEqual(expectedReturnValues.Length, results.Count, "Should have the same number of results as IActions."); + Assert.AreEqual(expectedReturnValues.Length, results.Count, "Should have the same number of results as IActions."); - for (int resultIndex = 0; resultIndex < results.Count; resultIndex++) - { - Assert.AreEqual(expectedReturnValues[resultIndex], results[resultIndex], "Results should be returned in the order of the actions in the ActionCollection."); - } + for (int resultIndex = 0; resultIndex < results.Count; resultIndex++) + { + Assert.AreEqual(expectedReturnValues[resultIndex], results[resultIndex], "Results should be returned in the order of the actions in the ActionCollection."); } } } diff --git a/src/BehaviorsSDKManaged/ManagedUnitTests/NavigateToPageActionTest.cs b/src/BehaviorsSDKManaged/ManagedUnitTests/NavigateToPageActionTest.cs index 701fd89..e82f145 100644 --- a/src/BehaviorsSDKManaged/ManagedUnitTests/NavigateToPageActionTest.cs +++ b/src/BehaviorsSDKManaged/ManagedUnitTests/NavigateToPageActionTest.cs @@ -6,69 +6,68 @@ using Microsoft.Xaml.Interactivity; using Windows.UI.Xaml; -namespace ManagedUnitTests +namespace ManagedUnitTests; + +[TestClass] +public class NavigateToPageActionTest { - [TestClass] - public class NavigateToPageActionTest - { - private static readonly string TestPageName = typeof(BlankPage).FullName; + private static readonly string TestPageName = typeof(BlankPage).FullName; - [UITestMethod] - public void Execute_SenderImplementsINavigate_NavigatesToSender() - { - // Arrange - TestVisualTreeHelper visualTreeHelper = new TestVisualTreeHelper(); - NavigateToPageAction action = new NavigateToPageAction(visualTreeHelper); - action.TargetPage = NavigateToPageActionTest.TestPageName; - NavigableStub navigateTarget = new NavigableStub(); + [UITestMethod] + public void Execute_SenderImplementsINavigate_NavigatesToSender() + { + // Arrange + TestVisualTreeHelper visualTreeHelper = new TestVisualTreeHelper(); + NavigateToPageAction action = new NavigateToPageAction(visualTreeHelper); + action.TargetPage = NavigateToPageActionTest.TestPageName; + NavigableStub navigateTarget = new NavigableStub(); - // Act - bool success = (bool)action.Execute(navigateTarget, null); + // Act + bool success = (bool)action.Execute(navigateTarget, null); - // Assert - Assert.IsTrue(success); - Assert.AreEqual(NavigateToPageActionTest.TestPageName, navigateTarget.NavigatedTypeFullName); - } + // Assert + Assert.IsTrue(success); + Assert.AreEqual(NavigateToPageActionTest.TestPageName, navigateTarget.NavigatedTypeFullName); + } - [UITestMethod] - public void Execute_SenderDoesNotImplementINavigate_NavigatesToAncestor() - { - // Arrange - TestVisualTreeHelper visualTreeHelper = new TestVisualTreeHelper(); - NavigateToPageAction action = new NavigateToPageAction(visualTreeHelper); - action.TargetPage = NavigateToPageActionTest.TestPageName; - DependencyObject sender = new SimpleDependencyObject(); - NavigableStub navigateTarget = new NavigableStub(); - visualTreeHelper.AddChild(navigateTarget, sender); + [UITestMethod] + public void Execute_SenderDoesNotImplementINavigate_NavigatesToAncestor() + { + // Arrange + TestVisualTreeHelper visualTreeHelper = new TestVisualTreeHelper(); + NavigateToPageAction action = new NavigateToPageAction(visualTreeHelper); + action.TargetPage = NavigateToPageActionTest.TestPageName; + DependencyObject sender = new SimpleDependencyObject(); + NavigableStub navigateTarget = new NavigableStub(); + visualTreeHelper.AddChild(navigateTarget, sender); - // Act - bool success = (bool)action.Execute(sender, null); + // Act + bool success = (bool)action.Execute(sender, null); - // Assert - Assert.IsTrue(success); - Assert.AreEqual(NavigateToPageActionTest.TestPageName, navigateTarget.NavigatedTypeFullName); - } + // Assert + Assert.IsTrue(success); + Assert.AreEqual(NavigateToPageActionTest.TestPageName, navigateTarget.NavigatedTypeFullName); + } - [UITestMethod] - public void Execute_NoAncestorImplementsINavigate_Fails() - { - // Arrange - TestVisualTreeHelper visualTreeHelper = new TestVisualTreeHelper(); - NavigateToPageAction action = new NavigateToPageAction(visualTreeHelper); - action.TargetPage = NavigateToPageActionTest.TestPageName; - DependencyObject sender = new SimpleDependencyObject(); - DependencyObject parent = new SimpleDependencyObject(); - visualTreeHelper.AddChild(parent, sender); + [UITestMethod] + public void Execute_NoAncestorImplementsINavigate_Fails() + { + // Arrange + TestVisualTreeHelper visualTreeHelper = new TestVisualTreeHelper(); + NavigateToPageAction action = new NavigateToPageAction(visualTreeHelper); + action.TargetPage = NavigateToPageActionTest.TestPageName; + DependencyObject sender = new SimpleDependencyObject(); + DependencyObject parent = new SimpleDependencyObject(); + visualTreeHelper.AddChild(parent, sender); - // Act - bool success = (bool)action.Execute(sender, null); + // Act + bool success = (bool)action.Execute(sender, null); - // Assert - Assert.IsFalse(success); - } + // Assert + Assert.IsFalse(success); + } - private class SimpleDependencyObject : DependencyObject - { - } + private class SimpleDependencyObject : DependencyObject + { } } diff --git a/src/BehaviorsSDKManaged/ManagedUnitTests/Stubs.cs b/src/BehaviorsSDKManaged/ManagedUnitTests/Stubs.cs index 370e263..a307fc1 100644 --- a/src/BehaviorsSDKManaged/ManagedUnitTests/Stubs.cs +++ b/src/BehaviorsSDKManaged/ManagedUnitTests/Stubs.cs @@ -7,414 +7,413 @@ using Windows.UI.Xaml.Data; using Windows.UI.Xaml.Navigation; -namespace ManagedUnitTests +namespace ManagedUnitTests; + +public class StubBehavior : DependencyObject, IBehavior { - public class StubBehavior : DependencyObject, IBehavior + public int AttachCount { - public int AttachCount - { - get; - private set; - } - - public int DetachCount - { - get; - private set; - } + get; + private set; + } - public ActionCollection Actions - { - get; - private set; - } + public int DetachCount + { + get; + private set; + } - public StubBehavior() - { - this.Actions = new ActionCollection(); - } + public ActionCollection Actions + { + get; + private set; + } - public DependencyObject AssociatedObject - { - get; - private set; - } + public StubBehavior() + { + this.Actions = new ActionCollection(); + } - public void Attach(DependencyObject dependencyObject) - { - this.AssociatedObject = dependencyObject; - this.AttachCount++; - } + public DependencyObject AssociatedObject + { + get; + private set; + } - public void Detach() - { - this.AssociatedObject = null; - this.DetachCount++; - } + public void Attach(DependencyObject dependencyObject) + { + this.AssociatedObject = dependencyObject; + this.AttachCount++; + } - public IEnumerable Execute(object sender, object parameter) - { - return Interaction.ExecuteActions(sender, this.Actions, parameter); - } + public void Detach() + { + this.AssociatedObject = null; + this.DetachCount++; } - public class StubAction : DependencyObject, IAction + public IEnumerable Execute(object sender, object parameter) { - private readonly object _returnValue; + return Interaction.ExecuteActions(sender, this.Actions, parameter); + } +} - public StubAction() - { - this._returnValue = null; - } +public class StubAction : DependencyObject, IAction +{ + private readonly object _returnValue; - public StubAction(object returnValue) - { - this._returnValue = returnValue; - } + public StubAction() + { + this._returnValue = null; + } - public object Sender - { - get; - private set; - } + public StubAction(object returnValue) + { + this._returnValue = returnValue; + } - public object Parameter - { - get; - private set; - } + public object Sender + { + get; + private set; + } - public int ExecuteCount - { - get; - private set; - } + public object Parameter + { + get; + private set; + } - public object Execute(object sender, object parameter) - { - this.ExecuteCount++; - this.Sender = sender; - this.Parameter = parameter; - return this._returnValue; - } + public int ExecuteCount + { + get; + private set; } - public class EventObjectStub : DependencyObject + public object Execute(object sender, object parameter) { - public string Name; + this.ExecuteCount++; + this.Sender = sender; + this.Parameter = parameter; + return this._returnValue; + } +} - public delegate void IntEventHandler(int i); +public class EventObjectStub : DependencyObject +{ + public string Name; - public event EventHandler StubEvent; - public event EventHandler StubEvent2; - public event IntEventHandler IntEvent; - public event EventHandler Click; + public delegate void IntEventHandler(int i); - public EventObjectStub(string name = null) - { - this.Name = name; - } + public event EventHandler StubEvent; + public event EventHandler StubEvent2; + public event IntEventHandler IntEvent; + public event EventHandler Click; - public void FireStubEvent() - { - if (this.StubEvent != null) - { - this.StubEvent.Invoke(this, new EventArgs()); - } - } + public EventObjectStub(string name = null) + { + this.Name = name; + } - public void FireClickEvent() + public void FireStubEvent() + { + if (this.StubEvent != null) { - if (this.Click != null) - { - this.Click.Invoke(this, new EventArgs()); - } + this.StubEvent.Invoke(this, new EventArgs()); } + } - public void FireStubEvent2() + public void FireClickEvent() + { + if (this.Click != null) { - if (this.StubEvent2 != null) - { - this.StubEvent2(this, new EventArgs()); - } + this.Click.Invoke(this, new EventArgs()); } + } - public void FireIntEvent() + public void FireStubEvent2() + { + if (this.StubEvent2 != null) { - if (this.IntEvent != null) - { - this.IntEvent(0); - } + this.StubEvent2(this, new EventArgs()); } } - public class ClrEventClassStub + public void FireIntEvent() { - public event EventHandler Event; - public static readonly string EventName = "Event"; - - public void Fire() + if (this.IntEvent != null) { - if (this.Event != null) - { - this.Event(this, EventArgs.Empty); - } + this.IntEvent(0); } } +} - public class ChangePropertyActionTargetStub - { - public const string DoublePropertyName = "DoubleProperty"; - public const string StringPropertyName = "StringProperty"; - public const string ObjectPropertyName = "ObjectProperty"; - public const string AdditivePropertyName = "AdditiveProperty"; - public const string WriteOnlyPropertyName = "WriteOnlyProperty"; +public class ClrEventClassStub +{ + public event EventHandler Event; + public static readonly string EventName = "Event"; - public double DoubleProperty + public void Fire() + { + if (this.Event != null) { - get; - set; + this.Event(this, EventArgs.Empty); } + } +} - public string StringProperty - { - get; - set; - } +public class ChangePropertyActionTargetStub +{ + public const string DoublePropertyName = "DoubleProperty"; + public const string StringPropertyName = "StringProperty"; + public const string ObjectPropertyName = "ObjectProperty"; + public const string AdditivePropertyName = "AdditiveProperty"; + public const string WriteOnlyPropertyName = "WriteOnlyProperty"; - public object ObjectProperty - { - get; - set; - } + public double DoubleProperty + { + get; + set; + } - public object WriteOnlyProperty - { - set - { - } - } + public string StringProperty + { + get; + set; } - public class NavigateToPageActionTargetStub : Frame + public object ObjectProperty { - public bool HasNavigated - { - get; - private set; - } + get; + set; + } - public object LastParameter + public object WriteOnlyProperty + { + set { - get; - private set; } + } +} - public new bool Navigate(Type sourcePageType) - { - this.HasNavigated = true; - return true; - } +public class NavigateToPageActionTargetStub : Frame +{ + public bool HasNavigated + { + get; + private set; + } - public new bool Navigate(Type sourcePageType, object parameter) - { - this.HasNavigated = true; - this.LastParameter = parameter; + public object LastParameter + { + get; + private set; + } - return true; - } + public new bool Navigate(Type sourcePageType) + { + this.HasNavigated = true; + return true; } - public class MethodObjectStub : DependencyObject + public new bool Navigate(Type sourcePageType, object parameter) { - public string LastMethodCalled - { - get; - private set; - } + this.HasNavigated = true; + this.LastParameter = parameter; - public MethodObjectStub() - { - this.LastMethodCalled = "None"; - } + return true; + } +} - public void UniqueMethodWithNoParameters() - { - this.LastMethodCalled = "UniqueMethodWithNoParameters"; - } +public class MethodObjectStub : DependencyObject +{ + public string LastMethodCalled + { + get; + private set; + } - public void DuplicatedMethod() - { - this.LastMethodCalled = "DuplicatedMethodWithNoParameters"; - } + public MethodObjectStub() + { + this.LastMethodCalled = "None"; + } - public void DuplicatedMethod(object sender, EventArgs args) - { - this.LastMethodCalled = "DuplicatedMethodWithEventHandlerSignature"; - } + public void UniqueMethodWithNoParameters() + { + this.LastMethodCalled = "UniqueMethodWithNoParameters"; + } - public void DuplicatedMethod(object sender, StubEventArgs args) - { - this.LastMethodCalled = "DuplicatedMethodWithStubEventArgsSignature"; - } + public void DuplicatedMethod() + { + this.LastMethodCalled = "DuplicatedMethodWithNoParameters"; + } - private void AnotherDuplicateMethod() - { - this.LastMethodCalled = "HiddenAnotherDuplicateMethod"; - } + public void DuplicatedMethod(object sender, EventArgs args) + { + this.LastMethodCalled = "DuplicatedMethodWithEventHandlerSignature"; + } - public void AnotherDuplicateMethod(object sender, object args) - { - this.LastMethodCalled = "AnotherDuplicateMethod"; - } + public void DuplicatedMethod(object sender, StubEventArgs args) + { + this.LastMethodCalled = "DuplicatedMethodWithStubEventArgsSignature"; + } - public void AnotherDuplicateMethod(object sender, int args) - { - this.LastMethodCalled = "AnotherDuplicateMethodWithValueType"; - } + private void AnotherDuplicateMethod() + { + this.LastMethodCalled = "HiddenAnotherDuplicateMethod"; + } - public void IndistinguishableWithNullMethod(object sender, Nullable args) - { - this.LastMethodCalled = "NullableIndistinguishableWithNullMethod"; - } + public void AnotherDuplicateMethod(object sender, object args) + { + this.LastMethodCalled = "AnotherDuplicateMethod"; + } - public void IndistinguishableWithNullMethod(object sender, Button args) - { - this.LastMethodCalled = "ButtonIndistinguishableWithNullMethod"; - } + public void AnotherDuplicateMethod(object sender, int args) + { + this.LastMethodCalled = "AnotherDuplicateMethodWithValueType"; + } - public void IndistinguishableWithNullMethod(object sender, bool args) - { - this.LastMethodCalled = "BoolIndistinguishableWithNullMethod"; - } + public void IndistinguishableWithNullMethod(object sender, Nullable args) + { + this.LastMethodCalled = "NullableIndistinguishableWithNullMethod"; + } - public int IncompatibleReturnType() - { - this.LastMethodCalled = "IncompatibleReturnType"; - return 0; - } + public void IndistinguishableWithNullMethod(object sender, Button args) + { + this.LastMethodCalled = "ButtonIndistinguishableWithNullMethod"; + } - public void IncompatibleParameters(double d) - { - this.LastMethodCalled = "IncompatibleParameters"; - } + public void IndistinguishableWithNullMethod(object sender, bool args) + { + this.LastMethodCalled = "BoolIndistinguishableWithNullMethod"; } - public class StubEventArgs : EventArgs + public int IncompatibleReturnType() { + this.LastMethodCalled = "IncompatibleReturnType"; + return 0; } - public class StubCommand : ICommand + public void IncompatibleParameters(double d) { - public event EventHandler CanExecuteChanged; + this.LastMethodCalled = "IncompatibleParameters"; + } +} - protected virtual void OnCanExecuteChanged(EventArgs e) - { - CanExecuteChanged?.Invoke(this, e); - } +public class StubEventArgs : EventArgs +{ +} - public int ExecutionCount - { - get; - private set; - } +public class StubCommand : ICommand +{ + public event EventHandler CanExecuteChanged; - public object LastParameter - { - get; - private set; - } + protected virtual void OnCanExecuteChanged(EventArgs e) + { + CanExecuteChanged?.Invoke(this, e); + } - public bool CanExecute(object parameter) - { - return true; - } + public int ExecutionCount + { + get; + private set; + } - public void Execute(object parameter) - { - this.ExecutionCount++; - string stringParam = parameter as string; - this.LastParameter = parameter; - } + public object LastParameter + { + get; + private set; } - public class BoolToTestParameterConverter : IValueConverter + public bool CanExecute(object parameter) { - public object Convert(object value, Type targetType, object parameter, string language) - { - bool boolValue; - bool boolParameter; - if (value == null || - !bool.TryParse(value.ToString(), out boolValue) || - !bool.TryParse(parameter.ToString(), out boolParameter)) - { - return null; - } - - string convertedValue = boolValue && boolParameter ? "TrueParameter" : "FalseParameter"; - return convertedValue + language; - } + return true; + } - public object ConvertBack(object value, Type targetType, object parameter, string language) - { - throw new NotImplementedException(); - } + public void Execute(object parameter) + { + this.ExecutionCount++; + string stringParam = parameter as string; + this.LastParameter = parameter; } +} - public class StubFrame : Frame +public class BoolToTestParameterConverter : IValueConverter +{ + public object Convert(object value, Type targetType, object parameter, string language) { - public bool NavigatedTo + bool boolValue; + bool boolParameter; + if (value == null || + !bool.TryParse(value.ToString(), out boolValue) || + !bool.TryParse(parameter.ToString(), out boolParameter)) { - get; - private set; + return null; } - public object Parameter - { - get; - private set; - } + string convertedValue = boolValue && boolParameter ? "TrueParameter" : "FalseParameter"; + return convertedValue + language; + } - public StubFrame() - { - this.Navigated += this.OnNavigated; - } + public object ConvertBack(object value, Type targetType, object parameter, string language) + { + throw new NotImplementedException(); + } +} - private void OnNavigated(object sender, NavigationEventArgs e) - { - this.NavigatedTo = true; - this.Parameter = e.Parameter; - } +public class StubFrame : Frame +{ + public bool NavigatedTo + { + get; + private set; } - public class StubPage : Page + public object Parameter { + get; + private set; } - public class NavigableStub : DependencyObject, INavigate + public StubFrame() { - public string NavigatedTypeFullName - { - get; - private set; - } + this.Navigated += this.OnNavigated; + } - public bool Navigate(Type sourcePageType) - { - this.NavigatedTypeFullName = sourcePageType.FullName; - return true; - } + private void OnNavigated(object sender, NavigationEventArgs e) + { + this.NavigatedTo = true; + this.Parameter = e.Parameter; + } +} + +public class StubPage : Page +{ +} + +public class NavigableStub : DependencyObject, INavigate +{ + public string NavigatedTypeFullName + { + get; + private set; } - public static class BehaviorTestHelper + public bool Navigate(Type sourcePageType) { - public static T CreateNamedElement(string name) where T : FrameworkElement, new() + this.NavigatedTypeFullName = sourcePageType.FullName; + return true; + } +} + +public static class BehaviorTestHelper +{ + public static T CreateNamedElement(string name) where T : FrameworkElement, new() + { + T frameworkElement = new T() { - T frameworkElement = new T() - { - Name = name - }; - return frameworkElement; - } + Name = name + }; + return frameworkElement; } } diff --git a/src/BehaviorsSDKManaged/ManagedUnitTests/TestUitilties.cs b/src/BehaviorsSDKManaged/ManagedUnitTests/TestUitilties.cs index 63928f2..e6b0673 100644 --- a/src/BehaviorsSDKManaged/ManagedUnitTests/TestUitilties.cs +++ b/src/BehaviorsSDKManaged/ManagedUnitTests/TestUitilties.cs @@ -5,44 +5,43 @@ using Windows.UI.Xaml; using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace ManagedUnitTests +namespace ManagedUnitTests; + +public static class TestUtilities { - public static class TestUtilities + /// + /// Handles the difference between InvalidOperationException in managed and native. + /// + public static void AssertThrowsInvalidOperationException(Action action) + { + Assert.ThrowsException(action); + } + + public static void AssertThrowsArgumentException(Action action) + { + Assert.ThrowsException(action); + } + + public static void AssertDetached(StubBehavior behavior) + { + Assert.AreEqual(1, behavior.DetachCount, "The Behavior should be detached."); + Assert.IsNull(behavior.AssociatedObject, "A Detached Behavior should have a null AssociatedObject."); + } + + public static void AssertNotDetached(StubBehavior behavior) + { + Assert.AreEqual(0, behavior.DetachCount, "The Behavior should not be detached."); + } + + public static void AssertAttached(StubBehavior behavior, DependencyObject associatedObject) + { + Assert.AreEqual(1, behavior.AttachCount, "The behavior should be attached."); + Assert.AreEqual(associatedObject, behavior.AssociatedObject, "The AssociatedObject of the Behavior should be what it was attached to."); + } + + public static void AssertNotAttached(StubBehavior behavior) { - /// - /// Handles the difference between InvalidOperationException in managed and native. - /// - public static void AssertThrowsInvalidOperationException(Action action) - { - Assert.ThrowsException(action); - } - - public static void AssertThrowsArgumentException(Action action) - { - Assert.ThrowsException(action); - } - - public static void AssertDetached(StubBehavior behavior) - { - Assert.AreEqual(1, behavior.DetachCount, "The Behavior should be detached."); - Assert.IsNull(behavior.AssociatedObject, "A Detached Behavior should have a null AssociatedObject."); - } - - public static void AssertNotDetached(StubBehavior behavior) - { - Assert.AreEqual(0, behavior.DetachCount, "The Behavior should not be detached."); - } - - public static void AssertAttached(StubBehavior behavior, DependencyObject associatedObject) - { - Assert.AreEqual(1, behavior.AttachCount, "The behavior should be attached."); - Assert.AreEqual(associatedObject, behavior.AssociatedObject, "The AssociatedObject of the Behavior should be what it was attached to."); - } - - public static void AssertNotAttached(StubBehavior behavior) - { - Assert.AreEqual(0, behavior.AttachCount, "The behavior should not be attached."); - Assert.IsNull(behavior.AssociatedObject, "The AssociatedObject should be null for a non-attached Behavior."); - } + Assert.AreEqual(0, behavior.AttachCount, "The behavior should not be attached."); + Assert.IsNull(behavior.AssociatedObject, "The AssociatedObject should be null for a non-attached Behavior."); } } diff --git a/src/BehaviorsSDKManaged/ManagedUnitTests/TestVisualTreeHelper.cs b/src/BehaviorsSDKManaged/ManagedUnitTests/TestVisualTreeHelper.cs index d9506ea..c4faf63 100644 --- a/src/BehaviorsSDKManaged/ManagedUnitTests/TestVisualTreeHelper.cs +++ b/src/BehaviorsSDKManaged/ManagedUnitTests/TestVisualTreeHelper.cs @@ -2,30 +2,29 @@ using Microsoft.Xaml.Interactivity.Utility; using Windows.UI.Xaml; -namespace ManagedUnitTests -{ - /// - /// Test impementation of VisualTreeHelper. Enables unit testing of code that - /// uses VisualTreeHelper without needing a real visual tree. - /// - internal class TestVisualTreeHelper : IVisualTreeHelper - { - private Dictionary _parents = new Dictionary(); +namespace ManagedUnitTests; - public void AddChild(DependencyObject parent, DependencyObject child) - { - this._parents[child] = parent; - } +/// +/// Test impementation of VisualTreeHelper. Enables unit testing of code that +/// uses VisualTreeHelper without needing a real visual tree. +/// +internal class TestVisualTreeHelper : IVisualTreeHelper +{ + private Dictionary _parents = new Dictionary(); - #region IVisualTreeHelper implementation + public void AddChild(DependencyObject parent, DependencyObject child) + { + this._parents[child] = parent; + } - public DependencyObject GetParent(DependencyObject child) - { - DependencyObject parent; - this._parents.TryGetValue(child, out parent); - return parent; - } + #region IVisualTreeHelper implementation - #endregion + public DependencyObject GetParent(DependencyObject child) + { + DependencyObject parent; + this._parents.TryGetValue(child, out parent); + return parent; } + + #endregion } diff --git a/src/BehaviorsSDKManaged/ManagedUnitTests/UnitTestApp.xaml.cs b/src/BehaviorsSDKManaged/ManagedUnitTests/UnitTestApp.xaml.cs index 75acc18..12df05e 100644 --- a/src/BehaviorsSDKManaged/ManagedUnitTests/UnitTestApp.xaml.cs +++ b/src/BehaviorsSDKManaged/ManagedUnitTests/UnitTestApp.xaml.cs @@ -15,88 +15,87 @@ using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; -namespace ManagedUnitTests +namespace ManagedUnitTests; + +/// +/// Provides application-specific behavior to supplement the default Application class. +/// +sealed partial class App : Application { /// - /// Provides application-specific behavior to supplement the default Application class. + /// Initializes the singleton application object. This is the first line of authored code + /// executed, and as such is the logical equivalent of main() or WinMain(). /// - sealed partial class App : Application + public App() { - /// - /// Initializes the singleton application object. This is the first line of authored code - /// executed, and as such is the logical equivalent of main() or WinMain(). - /// - public App() - { - this.InitializeComponent(); - this.Suspending += OnSuspending; - } + this.InitializeComponent(); + this.Suspending += OnSuspending; + } - /// - /// Invoked when the application is launched normally by the end user. Other entry points - /// will be used such as when the application is launched to open a specific file. - /// - /// Details about the launch request and process. - protected override void OnLaunched(LaunchActivatedEventArgs e) - { + /// + /// Invoked when the application is launched normally by the end user. Other entry points + /// will be used such as when the application is launched to open a specific file. + /// + /// Details about the launch request and process. + protected override void OnLaunched(LaunchActivatedEventArgs e) + { #if DEBUG - if (System.Diagnostics.Debugger.IsAttached) - { - this.DebugSettings.EnableFrameRateCounter = true; - } + if (System.Diagnostics.Debugger.IsAttached) + { + this.DebugSettings.EnableFrameRateCounter = true; + } #endif - Frame rootFrame = Window.Current.Content as Frame; + Frame rootFrame = Window.Current.Content as Frame; - // Do not repeat app initialization when the Window already has content, - // just ensure that the window is active - if (rootFrame == null) - { - // Create a Frame to act as the navigation context and navigate to the first page - rootFrame = new Frame(); - - rootFrame.NavigationFailed += OnNavigationFailed; + // Do not repeat app initialization when the Window already has content, + // just ensure that the window is active + if (rootFrame == null) + { + // Create a Frame to act as the navigation context and navigate to the first page + rootFrame = new Frame(); - if (e.PreviousExecutionState == ApplicationExecutionState.Terminated) - { - //TODO: Load state from previously suspended application - } + rootFrame.NavigationFailed += OnNavigationFailed; - // Place the frame in the current Window - Window.Current.Content = rootFrame; + if (e.PreviousExecutionState == ApplicationExecutionState.Terminated) + { + //TODO: Load state from previously suspended application } - - Microsoft.VisualStudio.TestPlatform.TestExecutor.UnitTestClient.CreateDefaultUI(); - // Ensure the current window is active - Window.Current.Activate(); - - Microsoft.VisualStudio.TestPlatform.TestExecutor.UnitTestClient.Run(e.Arguments); + // Place the frame in the current Window + Window.Current.Content = rootFrame; } + + Microsoft.VisualStudio.TestPlatform.TestExecutor.UnitTestClient.CreateDefaultUI(); - /// - /// Invoked when Navigation to a certain page fails - /// - /// The Frame which failed navigation - /// Details about the navigation failure - void OnNavigationFailed(object sender, NavigationFailedEventArgs e) - { - throw new Exception("Failed to load Page " + e.SourcePageType.FullName); - } + // Ensure the current window is active + Window.Current.Activate(); - /// - /// Invoked when application execution is being suspended. Application state is saved - /// without knowing whether the application will be terminated or resumed with the contents - /// of memory still intact. - /// - /// The source of the suspend request. - /// Details about the suspend request. - private void OnSuspending(object sender, SuspendingEventArgs e) - { - var deferral = e.SuspendingOperation.GetDeferral(); - //TODO: Save application state and stop any background activity - deferral.Complete(); - } + Microsoft.VisualStudio.TestPlatform.TestExecutor.UnitTestClient.Run(e.Arguments); + } + + /// + /// Invoked when Navigation to a certain page fails + /// + /// The Frame which failed navigation + /// Details about the navigation failure + void OnNavigationFailed(object sender, NavigationFailedEventArgs e) + { + throw new Exception("Failed to load Page " + e.SourcePageType.FullName); + } + + /// + /// Invoked when application execution is being suspended. Application state is saved + /// without knowing whether the application will be terminated or resumed with the contents + /// of memory still intact. + /// + /// The source of the suspend request. + /// Details about the suspend request. + private void OnSuspending(object sender, SuspendingEventArgs e) + { + var deferral = e.SuspendingOperation.GetDeferral(); + //TODO: Save application state and stop any background activity + deferral.Complete(); } } diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Design/MetadataTableProvider.DesignerIsolation.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Design/MetadataTableProvider.DesignerIsolation.cs index 36febd2..18a50f0 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Design/MetadataTableProvider.DesignerIsolation.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Design/MetadataTableProvider.DesignerIsolation.cs @@ -4,53 +4,52 @@ using System; using Microsoft.Xaml.Interactivity; -namespace Microsoft.Xaml.Interactivity.Design +namespace Microsoft.Xaml.Interactivity.Design; + +partial class MetadataTableProvider { - partial class MetadataTableProvider + private void AddAttribute(Type type, Attribute attribute) { - private void AddAttribute(Type type, Attribute attribute) - { - _attributeTableBuilder.AddCustomAttributes(type, attribute); - } + _attributeTableBuilder.AddCustomAttributes(type, attribute); + } - private void AddAttributes(Type type, params Attribute[] attributes) + private void AddAttributes(Type type, params Attribute[] attributes) + { + foreach (Attribute attribute in attributes) { - foreach (Attribute attribute in attributes) - { - AddAttribute(type, attribute); - } + AddAttribute(type, attribute); } + } - private void AddAttribute(Type type, string propertyName, Attribute attribute) - { - _attributeTableBuilder.AddCustomAttributes(type, propertyName, attribute); - } + private void AddAttribute(Type type, string propertyName, Attribute attribute) + { + _attributeTableBuilder.AddCustomAttributes(type, propertyName, attribute); + } - private void AddAttributes(Type type, string propertyName, params Attribute[] attributes) + private void AddAttributes(Type type, string propertyName, params Attribute[] attributes) + { + foreach (Attribute attribute in attributes) { - foreach (Attribute attribute in attributes) - { - AddAttribute(type, propertyName, attribute); - } + AddAttribute(type, propertyName, attribute); } + } - /// - /// This class contains the types used by the older Extensibility APIs. - /// - private static class Targets - { - internal static readonly Type IncrementalUpdateBehavior = typeof(IncrementalUpdateBehavior); - internal static readonly Type EventTriggerBehavior = typeof(EventTriggerBehavior); - internal static readonly Type DataTriggerBehavior = typeof(DataTriggerBehavior); - internal static readonly Type ChangePropertyAction = typeof(ChangePropertyAction); - internal static readonly Type InvokeCommandAction = typeof(InvokeCommandAction); - internal static readonly Type ControlStoryboardAction = typeof(ControlStoryboardAction); - internal static readonly Type GoToStateAction = typeof(GoToStateAction); - internal static readonly Type NavigateToPageAction = typeof(NavigateToPageAction); - internal static readonly Type PlaySoundAction = typeof(PlaySoundAction); - internal static readonly Type CallMethodAction = typeof(CallMethodAction); - internal static readonly Type ActionCollection = typeof(ActionCollection); - internal static readonly Type BehaviorCollection = typeof(BehaviorCollection); - } + /// + /// This class contains the types used by the older Extensibility APIs. + /// + private static class Targets + { + internal static readonly Type IncrementalUpdateBehavior = typeof(IncrementalUpdateBehavior); + internal static readonly Type EventTriggerBehavior = typeof(EventTriggerBehavior); + internal static readonly Type DataTriggerBehavior = typeof(DataTriggerBehavior); + internal static readonly Type ChangePropertyAction = typeof(ChangePropertyAction); + internal static readonly Type InvokeCommandAction = typeof(InvokeCommandAction); + internal static readonly Type ControlStoryboardAction = typeof(ControlStoryboardAction); + internal static readonly Type GoToStateAction = typeof(GoToStateAction); + internal static readonly Type NavigateToPageAction = typeof(NavigateToPageAction); + internal static readonly Type PlaySoundAction = typeof(PlaySoundAction); + internal static readonly Type CallMethodAction = typeof(CallMethodAction); + internal static readonly Type ActionCollection = typeof(ActionCollection); + internal static readonly Type BehaviorCollection = typeof(BehaviorCollection); } } diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Design/MetadataTableProvider.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Design/MetadataTableProvider.cs index 2c392c4..39051bb 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Design/MetadataTableProvider.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Design/MetadataTableProvider.cs @@ -20,212 +20,211 @@ // Please note that both the .Design and .DesignTools project // use the same namespace: Microsoft.Xaml.Interactivity.Design -namespace Microsoft.Xaml.Interactivity.Design +namespace Microsoft.Xaml.Interactivity.Design; + +partial class MetadataTableProvider : IProvideAttributeTable { - partial class MetadataTableProvider : IProvideAttributeTable - { - private AttributeTableBuilder _attributeTableBuilder; + private AttributeTableBuilder _attributeTableBuilder; - public AttributeTable AttributeTable + public AttributeTable AttributeTable + { + get { - get + if (_attributeTableBuilder == null) { - if (_attributeTableBuilder == null) - { - _attributeTableBuilder = new AttributeTableBuilder(); - } - - #region IncrementalUpdateBehavior - AddAttributes(Targets.IncrementalUpdateBehavior, new DescriptionAttribute(Resources.Description_IncrementalUpdateBehavior)); - - AddAttributes(Targets.IncrementalUpdateBehavior, "Phase", - new DescriptionAttribute(Resources.Description_IncrementalUpdateBehavior_Phase), - new CategoryAttribute(Resources.Category_Common_Properties)); - #endregion - - #region EventTriggerBehavior - AddAttributes(Targets.EventTriggerBehavior, new DescriptionAttribute(Resources.Description_EventTriggerBehavior)); - - AddAttributes(Targets.EventTriggerBehavior, "EventName", - new DescriptionAttribute(Resources.Description_EventTriggerBehavior_EventName), - CreateEditorAttribute(), - new CategoryAttribute(Resources.Category_Common_Properties)); - - AddAttributes(Targets.EventTriggerBehavior, "SourceObject", - new DescriptionAttribute(Resources.Description_EventTriggerBehavior_SourceObject), - CreateEditorAttribute(), - new CategoryAttribute(Resources.Category_Common_Properties)); - - AddAttributes(Targets.EventTriggerBehavior, "Actions", - new DescriptionAttribute(Resources.Description_EventTriggerBehavior_Actions)); - #endregion - - #region DataTriggerBehavior - AddAttributes(Targets.DataTriggerBehavior, new DefaultBindingPropertyAttribute("Binding")); - - AddAttributes(Targets.DataTriggerBehavior, "Binding", - new DescriptionAttribute(Resources.Description_DataTriggerBehavior_Binding), - CreateEditorAttribute(), - new CategoryAttribute(Resources.Category_Common_Properties)); - - AddAttributes(Targets.DataTriggerBehavior, "ComparisonCondition", - new DescriptionAttribute(Resources.Description_DataTriggerBehavior_ComparisonCondition), - new CategoryAttribute(Resources.Category_Common_Properties)); - - AddAttributes(Targets.DataTriggerBehavior, "Value", - new DescriptionAttribute(Resources.Description_DataTriggerBehavior_Value), - new CategoryAttribute(Resources.Category_Common_Properties), - new TypeConverterAttribute(typeof(StringConverter))); - - AddAttributes(Targets.DataTriggerBehavior, "Actions", - new DescriptionAttribute(Resources.Description_DataTriggerBehavior_Actions)); - #endregion - - #region ChangePropertyAction - AddAttributes(Targets.ChangePropertyAction, new DescriptionAttribute(Resources.Description_ChangePropertyAction)); - - AddAttributes(Targets.ChangePropertyAction, "PropertyName", - CreateEditorAttribute(), - new CategoryAttribute(Resources.Category_Common_Properties), - new DescriptionAttribute(Resources.Description_ChangePropertyAction_PropertyName)); - - AddAttributes(Targets.ChangePropertyAction, "TargetObject", - new DescriptionAttribute(Resources.Description_ChangePropertyAction_TargetObject), - CreateEditorAttribute(), - new CategoryAttribute(Resources.Category_Common_Properties)); - - AddAttributes(Targets.ChangePropertyAction, "Value", - new DescriptionAttribute(Resources.Description_ChangePropertyAction_Value), - new CategoryAttribute(Resources.Category_Common_Properties), - new BrowsableAttribute(false)); - - #endregion ChangePropertyAction - - #region InvokeCommandAction - AddAttributes(Targets.InvokeCommandAction, - new DescriptionAttribute(Resources.Description_InvokeCommandAction), - new DefaultBindingPropertyAttribute("Command")); - - AddAttributes(Targets.InvokeCommandAction, "Command", - new CategoryAttribute(Resources.Category_Common_Properties), - CreateEditorAttribute(), - new DescriptionAttribute(Resources.Description_InvokeCommandAction_Command)); - - AddAttributes(Targets.InvokeCommandAction, "CommandParameter", - new TypeConverterAttribute(typeof(StringConverter)), - new CategoryAttribute(Resources.Category_Common_Properties), - new DescriptionAttribute(Resources.Description_InvokeCommandAction_CommandParameter), - new EditorBrowsableAttribute(EditorBrowsableState.Advanced)); - - AddAttributes(Targets.InvokeCommandAction, "InputConverter", - new CategoryAttribute(Resources.Category_Common_Properties), - new DescriptionAttribute(Resources.Description_InvokeCommandAction_InputConverter), - new EditorBrowsableAttribute(EditorBrowsableState.Advanced)); - - AddAttributes(Targets.InvokeCommandAction, "InputConverterParameter", - new TypeConverterAttribute(typeof(StringConverter)), - new CategoryAttribute(Resources.Category_Common_Properties), - new DescriptionAttribute(Resources.Description_InvokeCommandAction_InputConverterParameter), - new EditorBrowsableAttribute(EditorBrowsableState.Advanced)); - - AddAttributes(Targets.InvokeCommandAction, "InputConverterLanguage", - new CategoryAttribute(Resources.Category_Common_Properties), - new DescriptionAttribute(Resources.Description_InvokeCommandAction_InputConverterLanguage), - new TypeConverterAttribute(typeof(CultureInfoNamesConverter)), - new EditorBrowsableAttribute(EditorBrowsableState.Advanced)); - #endregion - - #region ControlStoryboardAction - AddAttributes(Targets.ControlStoryboardAction, new DescriptionAttribute(Resources.Description_ControlStoryboardAction)); - - AddAttributes(Targets.ControlStoryboardAction, "ControlStoryboardOption", - new DescriptionAttribute(Resources.Description_ControlStoryboardAction_ControlStoryboardOption), - new CategoryAttribute(Resources.Category_Common_Properties)); - - AddAttributes(Targets.ControlStoryboardAction, "Storyboard", - new DescriptionAttribute(Resources.Description_ControlStoryboardAction_Storyboard), - new CategoryAttribute(Resources.Category_Common_Properties), - CreateEditorAttribute(), - new TypeConverterAttribute(typeof(TypeConverter))); - #endregion - - #region GotoStateAction - AddAttributes(Targets.GoToStateAction, new DescriptionAttribute(Resources.Description_GoToStateAction)); - - AddAttributes(Targets.GoToStateAction, "StateName", - CreateEditorAttribute(), - new DescriptionAttribute(Resources.Description_GoToStateAction_StateName), - new CategoryAttribute(Resources.Category_Common_Properties)); - - AddAttributes(Targets.GoToStateAction, "UseTransitions", - new DescriptionAttribute(Resources.Description_GoToStateAction_UseTransitions), - new CategoryAttribute(Resources.Category_Common_Properties)); - - AddAttributes(Targets.GoToStateAction, "TargetObject", - new CategoryAttribute(Resources.Category_Common_Properties), - new DescriptionAttribute(Resources.Description_GoToStateAction_TargetObject), - CreateEditorAttribute()); - #endregion - - #region NavigateToPageAction - AddAttributes(Targets.NavigateToPageAction, new DescriptionAttribute(Resources.Description_NavigateToPageAction)); - - AddAttributes(Targets.NavigateToPageAction, "TargetPage", - CreateEditorAttribute(), - new DescriptionAttribute(Resources.Description_NavigateToPageAction_TargetPage), - new CategoryAttribute(Resources.Category_Common_Properties)); - - AddAttributes(Targets.NavigateToPageAction, "Parameter", - new DescriptionAttribute(Resources.Description_NavigateToPageAction_Parameter), - new CategoryAttribute(Resources.Category_Common_Properties), - new TypeConverterAttribute(typeof(StringConverter))); - #endregion - - #region PlaySoundAction - AddAttributes(Targets.PlaySoundAction, new DescriptionAttribute(Resources.Description_PlaySoundAction)); - - AddAttributes(Targets.PlaySoundAction, "Source", - CreateEditorAttribute(), - new DescriptionAttribute(Resources.Description_PlaySoundAction_Source), - new CategoryAttribute(Resources.Category_Common_Properties)); - - AddAttributes(Targets.PlaySoundAction, "Volume", - new NumberRangesAttribute(0, 0, 1, 1, canBeAuto: false), - new NumberIncrementsAttribute(0.001, 0.01, 0.1), - new DescriptionAttribute(Resources.Description_PlaySoundAction_Volume), - new CategoryAttribute(Resources.Category_Common_Properties)); - #endregion - - #region CallMethodAction - PropertyOrder order = PropertyOrder.Default; - - AddAttributes(Targets.CallMethodAction, new DescriptionAttribute(Resources.Description_CallMethodAction), - new DefaultBindingPropertyAttribute("TargetObject")); - - AddAttributes(Targets.CallMethodAction, "TargetObject", - new PropertyOrderAttribute(order = PropertyOrder.CreateAfter(order)), - new DescriptionAttribute(Resources.Description_CallMethodAction_TargetObject), - CreateEditorAttribute(), - new CategoryAttribute(Resources.Category_Common_Properties)); - - AddAttributes(Targets.CallMethodAction, "MethodName", - new PropertyOrderAttribute(order = PropertyOrder.CreateAfter(order)), - new DescriptionAttribute(Resources.Description_CallMethodAction_MethodName), - new CategoryAttribute(Resources.Category_Common_Properties)); - #endregion - - #region Collections - AddAttributes(Targets.ActionCollection, new CategoryAttribute(Resources.Category_Name_Actions)); - AddAttributes(Targets.BehaviorCollection, new ToolboxBrowsableAttribute(false)); - #endregion - - return _attributeTableBuilder.CreateTable(); + _attributeTableBuilder = new AttributeTableBuilder(); } - } - private static EditorAttribute CreateEditorAttribute() where T : PropertyValueEditor - { - return PropertyValueEditor.CreateEditorAttribute(typeof(T)); + #region IncrementalUpdateBehavior + AddAttributes(Targets.IncrementalUpdateBehavior, new DescriptionAttribute(Resources.Description_IncrementalUpdateBehavior)); + + AddAttributes(Targets.IncrementalUpdateBehavior, "Phase", + new DescriptionAttribute(Resources.Description_IncrementalUpdateBehavior_Phase), + new CategoryAttribute(Resources.Category_Common_Properties)); + #endregion + + #region EventTriggerBehavior + AddAttributes(Targets.EventTriggerBehavior, new DescriptionAttribute(Resources.Description_EventTriggerBehavior)); + + AddAttributes(Targets.EventTriggerBehavior, "EventName", + new DescriptionAttribute(Resources.Description_EventTriggerBehavior_EventName), + CreateEditorAttribute(), + new CategoryAttribute(Resources.Category_Common_Properties)); + + AddAttributes(Targets.EventTriggerBehavior, "SourceObject", + new DescriptionAttribute(Resources.Description_EventTriggerBehavior_SourceObject), + CreateEditorAttribute(), + new CategoryAttribute(Resources.Category_Common_Properties)); + + AddAttributes(Targets.EventTriggerBehavior, "Actions", + new DescriptionAttribute(Resources.Description_EventTriggerBehavior_Actions)); + #endregion + + #region DataTriggerBehavior + AddAttributes(Targets.DataTriggerBehavior, new DefaultBindingPropertyAttribute("Binding")); + + AddAttributes(Targets.DataTriggerBehavior, "Binding", + new DescriptionAttribute(Resources.Description_DataTriggerBehavior_Binding), + CreateEditorAttribute(), + new CategoryAttribute(Resources.Category_Common_Properties)); + + AddAttributes(Targets.DataTriggerBehavior, "ComparisonCondition", + new DescriptionAttribute(Resources.Description_DataTriggerBehavior_ComparisonCondition), + new CategoryAttribute(Resources.Category_Common_Properties)); + + AddAttributes(Targets.DataTriggerBehavior, "Value", + new DescriptionAttribute(Resources.Description_DataTriggerBehavior_Value), + new CategoryAttribute(Resources.Category_Common_Properties), + new TypeConverterAttribute(typeof(StringConverter))); + + AddAttributes(Targets.DataTriggerBehavior, "Actions", + new DescriptionAttribute(Resources.Description_DataTriggerBehavior_Actions)); + #endregion + + #region ChangePropertyAction + AddAttributes(Targets.ChangePropertyAction, new DescriptionAttribute(Resources.Description_ChangePropertyAction)); + + AddAttributes(Targets.ChangePropertyAction, "PropertyName", + CreateEditorAttribute(), + new CategoryAttribute(Resources.Category_Common_Properties), + new DescriptionAttribute(Resources.Description_ChangePropertyAction_PropertyName)); + + AddAttributes(Targets.ChangePropertyAction, "TargetObject", + new DescriptionAttribute(Resources.Description_ChangePropertyAction_TargetObject), + CreateEditorAttribute(), + new CategoryAttribute(Resources.Category_Common_Properties)); + + AddAttributes(Targets.ChangePropertyAction, "Value", + new DescriptionAttribute(Resources.Description_ChangePropertyAction_Value), + new CategoryAttribute(Resources.Category_Common_Properties), + new BrowsableAttribute(false)); + + #endregion ChangePropertyAction + + #region InvokeCommandAction + AddAttributes(Targets.InvokeCommandAction, + new DescriptionAttribute(Resources.Description_InvokeCommandAction), + new DefaultBindingPropertyAttribute("Command")); + + AddAttributes(Targets.InvokeCommandAction, "Command", + new CategoryAttribute(Resources.Category_Common_Properties), + CreateEditorAttribute(), + new DescriptionAttribute(Resources.Description_InvokeCommandAction_Command)); + + AddAttributes(Targets.InvokeCommandAction, "CommandParameter", + new TypeConverterAttribute(typeof(StringConverter)), + new CategoryAttribute(Resources.Category_Common_Properties), + new DescriptionAttribute(Resources.Description_InvokeCommandAction_CommandParameter), + new EditorBrowsableAttribute(EditorBrowsableState.Advanced)); + + AddAttributes(Targets.InvokeCommandAction, "InputConverter", + new CategoryAttribute(Resources.Category_Common_Properties), + new DescriptionAttribute(Resources.Description_InvokeCommandAction_InputConverter), + new EditorBrowsableAttribute(EditorBrowsableState.Advanced)); + + AddAttributes(Targets.InvokeCommandAction, "InputConverterParameter", + new TypeConverterAttribute(typeof(StringConverter)), + new CategoryAttribute(Resources.Category_Common_Properties), + new DescriptionAttribute(Resources.Description_InvokeCommandAction_InputConverterParameter), + new EditorBrowsableAttribute(EditorBrowsableState.Advanced)); + + AddAttributes(Targets.InvokeCommandAction, "InputConverterLanguage", + new CategoryAttribute(Resources.Category_Common_Properties), + new DescriptionAttribute(Resources.Description_InvokeCommandAction_InputConverterLanguage), + new TypeConverterAttribute(typeof(CultureInfoNamesConverter)), + new EditorBrowsableAttribute(EditorBrowsableState.Advanced)); + #endregion + + #region ControlStoryboardAction + AddAttributes(Targets.ControlStoryboardAction, new DescriptionAttribute(Resources.Description_ControlStoryboardAction)); + + AddAttributes(Targets.ControlStoryboardAction, "ControlStoryboardOption", + new DescriptionAttribute(Resources.Description_ControlStoryboardAction_ControlStoryboardOption), + new CategoryAttribute(Resources.Category_Common_Properties)); + + AddAttributes(Targets.ControlStoryboardAction, "Storyboard", + new DescriptionAttribute(Resources.Description_ControlStoryboardAction_Storyboard), + new CategoryAttribute(Resources.Category_Common_Properties), + CreateEditorAttribute(), + new TypeConverterAttribute(typeof(TypeConverter))); + #endregion + + #region GotoStateAction + AddAttributes(Targets.GoToStateAction, new DescriptionAttribute(Resources.Description_GoToStateAction)); + + AddAttributes(Targets.GoToStateAction, "StateName", + CreateEditorAttribute(), + new DescriptionAttribute(Resources.Description_GoToStateAction_StateName), + new CategoryAttribute(Resources.Category_Common_Properties)); + + AddAttributes(Targets.GoToStateAction, "UseTransitions", + new DescriptionAttribute(Resources.Description_GoToStateAction_UseTransitions), + new CategoryAttribute(Resources.Category_Common_Properties)); + + AddAttributes(Targets.GoToStateAction, "TargetObject", + new CategoryAttribute(Resources.Category_Common_Properties), + new DescriptionAttribute(Resources.Description_GoToStateAction_TargetObject), + CreateEditorAttribute()); + #endregion + + #region NavigateToPageAction + AddAttributes(Targets.NavigateToPageAction, new DescriptionAttribute(Resources.Description_NavigateToPageAction)); + + AddAttributes(Targets.NavigateToPageAction, "TargetPage", + CreateEditorAttribute(), + new DescriptionAttribute(Resources.Description_NavigateToPageAction_TargetPage), + new CategoryAttribute(Resources.Category_Common_Properties)); + + AddAttributes(Targets.NavigateToPageAction, "Parameter", + new DescriptionAttribute(Resources.Description_NavigateToPageAction_Parameter), + new CategoryAttribute(Resources.Category_Common_Properties), + new TypeConverterAttribute(typeof(StringConverter))); + #endregion + + #region PlaySoundAction + AddAttributes(Targets.PlaySoundAction, new DescriptionAttribute(Resources.Description_PlaySoundAction)); + + AddAttributes(Targets.PlaySoundAction, "Source", + CreateEditorAttribute(), + new DescriptionAttribute(Resources.Description_PlaySoundAction_Source), + new CategoryAttribute(Resources.Category_Common_Properties)); + + AddAttributes(Targets.PlaySoundAction, "Volume", + new NumberRangesAttribute(0, 0, 1, 1, canBeAuto: false), + new NumberIncrementsAttribute(0.001, 0.01, 0.1), + new DescriptionAttribute(Resources.Description_PlaySoundAction_Volume), + new CategoryAttribute(Resources.Category_Common_Properties)); + #endregion + + #region CallMethodAction + PropertyOrder order = PropertyOrder.Default; + + AddAttributes(Targets.CallMethodAction, new DescriptionAttribute(Resources.Description_CallMethodAction), + new DefaultBindingPropertyAttribute("TargetObject")); + + AddAttributes(Targets.CallMethodAction, "TargetObject", + new PropertyOrderAttribute(order = PropertyOrder.CreateAfter(order)), + new DescriptionAttribute(Resources.Description_CallMethodAction_TargetObject), + CreateEditorAttribute(), + new CategoryAttribute(Resources.Category_Common_Properties)); + + AddAttributes(Targets.CallMethodAction, "MethodName", + new PropertyOrderAttribute(order = PropertyOrder.CreateAfter(order)), + new DescriptionAttribute(Resources.Description_CallMethodAction_MethodName), + new CategoryAttribute(Resources.Category_Common_Properties)); + #endregion + + #region Collections + AddAttributes(Targets.ActionCollection, new CategoryAttribute(Resources.Category_Name_Actions)); + AddAttributes(Targets.BehaviorCollection, new ToolboxBrowsableAttribute(false)); + #endregion + + return _attributeTableBuilder.CreateTable(); } } + + private static EditorAttribute CreateEditorAttribute() where T : PropertyValueEditor + { + return PropertyValueEditor.CreateEditorAttribute(typeof(T)); + } } \ No newline at end of file diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.DesignTools/MetadataTableProvider.SurfaceIsolation.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.DesignTools/MetadataTableProvider.SurfaceIsolation.cs index c38700b..67d1fe2 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.DesignTools/MetadataTableProvider.SurfaceIsolation.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.DesignTools/MetadataTableProvider.SurfaceIsolation.cs @@ -3,39 +3,38 @@ using System; -namespace Microsoft.Xaml.Interactivity.Design +namespace Microsoft.Xaml.Interactivity.Design; + +partial class MetadataTableProvider { - partial class MetadataTableProvider + private void AddAttributes(string typeIdentifier, params Attribute[] attributes) { - private void AddAttributes(string typeIdentifier, params Attribute[] attributes) - { - _attributeTableBuilder.AddCustomAttributes(typeIdentifier, attributes); - } + _attributeTableBuilder.AddCustomAttributes(typeIdentifier, attributes); + } - private void AddAttributes(string typeIdentifier, string propertyName, params Attribute[] attributes) - { - _attributeTableBuilder.AddCustomAttributes(typeIdentifier, propertyName, attributes); - } + private void AddAttributes(string typeIdentifier, string propertyName, params Attribute[] attributes) + { + _attributeTableBuilder.AddCustomAttributes(typeIdentifier, propertyName, attributes); + } - /// - /// This class contains the type names required by the new Extensibility APIs. - /// - private static class Targets - { - private const string rootNamespace = "Microsoft.Xaml.Interactivity."; + /// + /// This class contains the type names required by the new Extensibility APIs. + /// + private static class Targets + { + private const string rootNamespace = "Microsoft.Xaml.Interactivity."; - internal const string CallMethodAction = rootNamespace + "CallMethodAction"; - internal const string ChangePropertyAction = rootNamespace + "ChangePropertyAction"; - internal const string ControlStoryboardAction = rootNamespace + "ControlStoryboardAction"; - internal const string DataTriggerBehavior = rootNamespace + "DataTriggerBehavior"; - internal const string IncrementalUpdateBehavior = rootNamespace + "IncrementalUpdateBehavior"; - internal const string EventTriggerBehavior = rootNamespace + "EventTriggerBehavior"; - internal const string GoToStateAction = rootNamespace + "GoToStateAction"; - internal const string InvokeCommandAction = rootNamespace + "InvokeCommandAction"; - internal const string NavigateToPageAction = rootNamespace + "NavigateToPageAction"; - internal const string PlaySoundAction = rootNamespace + "PlaySoundAction"; - internal const string ActionCollection = rootNamespace + "ActionCollection"; - internal const string BehaviorCollection = rootNamespace + "BehaviorCollection"; - } + internal const string CallMethodAction = rootNamespace + "CallMethodAction"; + internal const string ChangePropertyAction = rootNamespace + "ChangePropertyAction"; + internal const string ControlStoryboardAction = rootNamespace + "ControlStoryboardAction"; + internal const string DataTriggerBehavior = rootNamespace + "DataTriggerBehavior"; + internal const string IncrementalUpdateBehavior = rootNamespace + "IncrementalUpdateBehavior"; + internal const string EventTriggerBehavior = rootNamespace + "EventTriggerBehavior"; + internal const string GoToStateAction = rootNamespace + "GoToStateAction"; + internal const string InvokeCommandAction = rootNamespace + "InvokeCommandAction"; + internal const string NavigateToPageAction = rootNamespace + "NavigateToPageAction"; + internal const string PlaySoundAction = rootNamespace + "PlaySoundAction"; + internal const string ActionCollection = rootNamespace + "ActionCollection"; + internal const string BehaviorCollection = rootNamespace + "BehaviorCollection"; } } diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/ActionCollection.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/ActionCollection.cs index 92682c7..3daff6d 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/ActionCollection.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/ActionCollection.cs @@ -10,45 +10,44 @@ using Windows.UI.Xaml; #endif -namespace Microsoft.Xaml.Interactivity +namespace Microsoft.Xaml.Interactivity; + +/// +/// Represents a collection of IActions. +/// +public sealed partial class ActionCollection : DependencyObjectCollection { /// - /// Represents a collection of IActions. + /// Initializes a new instance of the class. /// - public sealed partial class ActionCollection : DependencyObjectCollection + public ActionCollection() { - /// - /// Initializes a new instance of the class. - /// - public ActionCollection() - { - this.VectorChanged += this.ActionCollection_VectorChanged; - } + this.VectorChanged += this.ActionCollection_VectorChanged; + } - private void ActionCollection_VectorChanged(IObservableVector sender, IVectorChangedEventArgs eventArgs) - { - CollectionChange collectionChange = eventArgs.CollectionChange; + private void ActionCollection_VectorChanged(IObservableVector sender, IVectorChangedEventArgs eventArgs) + { + CollectionChange collectionChange = eventArgs.CollectionChange; - if (collectionChange == CollectionChange.Reset) - { - foreach (DependencyObject item in this) - { - ActionCollection.VerifyType(item); - } - } - else if (collectionChange == CollectionChange.ItemInserted || collectionChange == CollectionChange.ItemChanged) + if (collectionChange == CollectionChange.Reset) + { + foreach (DependencyObject item in this) { - DependencyObject changedItem = this[(int)eventArgs.Index]; - ActionCollection.VerifyType(changedItem); + ActionCollection.VerifyType(item); } } + else if (collectionChange == CollectionChange.ItemInserted || collectionChange == CollectionChange.ItemChanged) + { + DependencyObject changedItem = this[(int)eventArgs.Index]; + ActionCollection.VerifyType(changedItem); + } + } - private static void VerifyType(DependencyObject item) + private static void VerifyType(DependencyObject item) + { + if (!(item is IAction)) { - if (!(item is IAction)) - { - throw new InvalidOperationException(ResourceHelper.GetString("NonActionAddedToActionCollectionExceptionMessage")); - } + throw new InvalidOperationException(ResourceHelper.GetString("NonActionAddedToActionCollectionExceptionMessage")); } } } diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Behavior.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Behavior.cs index 30ace31..1911007 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Behavior.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Behavior.cs @@ -11,74 +11,73 @@ using Windows.UI.Xaml; #endif -namespace Microsoft.Xaml.Interactivity +namespace Microsoft.Xaml.Interactivity; + +/// +/// A base class for behaviors, implementing the basic plumbing of IBehavior +/// +public abstract class Behavior : DependencyObject, IBehavior { /// - /// A base class for behaviors, implementing the basic plumbing of IBehavior + /// Gets the to which the behavior is attached. /// - public abstract class Behavior : DependencyObject, IBehavior - { - /// - /// Gets the to which the behavior is attached. - /// - public DependencyObject AssociatedObject { get; private set; } + public DependencyObject AssociatedObject { get; private set; } - /// - /// Attaches the behavior to the specified . - /// - /// The to which to attach. - /// is null. - public void Attach(DependencyObject associatedObject) + /// + /// Attaches the behavior to the specified . + /// + /// The to which to attach. + /// is null. + public void Attach(DependencyObject associatedObject) + { + if (associatedObject == this.AssociatedObject || global::Windows.ApplicationModel.DesignMode.DesignModeEnabled) { - if (associatedObject == this.AssociatedObject || global::Windows.ApplicationModel.DesignMode.DesignModeEnabled) - { - return; - } + return; + } - if (this.AssociatedObject != null) - { - throw new InvalidOperationException(string.Format( - CultureInfo.CurrentCulture, - ResourceHelper.CannotAttachBehaviorMultipleTimesExceptionMessage, - associatedObject, - this.AssociatedObject)); - } + if (this.AssociatedObject != null) + { + throw new InvalidOperationException(string.Format( + CultureInfo.CurrentCulture, + ResourceHelper.CannotAttachBehaviorMultipleTimesExceptionMessage, + associatedObject, + this.AssociatedObject)); + } - Debug.Assert(associatedObject != null, "Cannot attach the behavior to a null object."); + Debug.Assert(associatedObject != null, "Cannot attach the behavior to a null object."); - if (associatedObject == null) throw new ArgumentNullException(nameof(associatedObject)); + if (associatedObject == null) throw new ArgumentNullException(nameof(associatedObject)); - AssociatedObject = associatedObject; - OnAttached(); - } + AssociatedObject = associatedObject; + OnAttached(); + } - /// - /// Detaches the behaviors from the . - /// - public void Detach() - { - OnDetaching(); - AssociatedObject = null; - } + /// + /// Detaches the behaviors from the . + /// + public void Detach() + { + OnDetaching(); + AssociatedObject = null; + } - /// - /// Called after the behavior is attached to the . - /// - /// - /// Override this to hook up functionality to the - /// - protected virtual void OnAttached() - { - } + /// + /// Called after the behavior is attached to the . + /// + /// + /// Override this to hook up functionality to the + /// + protected virtual void OnAttached() + { + } - /// - /// Called when the behavior is being detached from its . - /// - /// - /// Override this to unhook functionality from the - /// - protected virtual void OnDetaching() - { - } + /// + /// Called when the behavior is being detached from its . + /// + /// + /// Override this to unhook functionality from the + /// + protected virtual void OnDetaching() + { } } diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/BehaviorCollection.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/BehaviorCollection.cs index 8330403..9a3129e 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/BehaviorCollection.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/BehaviorCollection.cs @@ -12,191 +12,190 @@ using Windows.UI.Xaml; #endif -namespace Microsoft.Xaml.Interactivity +namespace Microsoft.Xaml.Interactivity; + +/// +/// Represents a collection of IBehaviors with a shared . +/// +public sealed partial class BehaviorCollection : DependencyObjectCollection { + // After a VectorChanged event we need to compare the current state of the collection + // with the old collection so that we can call Detach on all removed items. + private readonly List _oldCollection = new List(); + + /// + /// Initializes a new instance of the class. + /// + public BehaviorCollection() + { + this.VectorChanged += this.BehaviorCollection_VectorChanged; + } + + /// + /// Gets the to which the is attached. + /// + public DependencyObject AssociatedObject { + get; + private set; + } + /// - /// Represents a collection of IBehaviors with a shared . + /// Attaches the collection of behaviors to the specified . /// - public sealed partial class BehaviorCollection : DependencyObjectCollection + /// The to which to attach. + /// + /// The is already attached to a different . + /// + public void Attach(DependencyObject associatedObject) { - // After a VectorChanged event we need to compare the current state of the collection - // with the old collection so that we can call Detach on all removed items. - private readonly List _oldCollection = new List(); - - /// - /// Initializes a new instance of the class. - /// - public BehaviorCollection() + if (associatedObject == this.AssociatedObject) { - this.VectorChanged += this.BehaviorCollection_VectorChanged; + return; } - /// - /// Gets the to which the is attached. - /// - public DependencyObject AssociatedObject { - get; - private set; + if (global::Windows.ApplicationModel.DesignMode.DesignModeEnabled) + { + return; } - /// - /// Attaches the collection of behaviors to the specified . - /// - /// The to which to attach. - /// - /// The is already attached to a different . - /// - public void Attach(DependencyObject associatedObject) + if (this.AssociatedObject != null) { - if (associatedObject == this.AssociatedObject) - { - return; - } - - if (global::Windows.ApplicationModel.DesignMode.DesignModeEnabled) - { - return; - } + throw new InvalidOperationException(ResourceHelper.GetString("CannotAttachBehaviorMultipleTimesExceptionMessage")); + } - if (this.AssociatedObject != null) - { - throw new InvalidOperationException(ResourceHelper.GetString("CannotAttachBehaviorMultipleTimesExceptionMessage")); - } + Debug.Assert(associatedObject != null, "The previous checks should keep us from ever setting null here."); + this.AssociatedObject = associatedObject; - Debug.Assert(associatedObject != null, "The previous checks should keep us from ever setting null here."); - this.AssociatedObject = associatedObject; + foreach (DependencyObject item in this) + { + IBehavior behavior = (IBehavior)item; + behavior.Attach(this.AssociatedObject); + } + } - foreach (DependencyObject item in this) + /// + /// Detaches the collection of behaviors from the . + /// + public void Detach() + { + foreach (DependencyObject item in this) + { + IBehavior behaviorItem = (IBehavior)item; + if (behaviorItem.AssociatedObject != null) { - IBehavior behavior = (IBehavior)item; - behavior.Attach(this.AssociatedObject); + behaviorItem.Detach(); } } - /// - /// Detaches the collection of behaviors from the . - /// - public void Detach() + this.AssociatedObject = null; + this._oldCollection.Clear(); + } + + private void BehaviorCollection_VectorChanged(IObservableVector sender, IVectorChangedEventArgs eventArgs) + { + if (eventArgs.CollectionChange == CollectionChange.Reset) { - foreach (DependencyObject item in this) + foreach (IBehavior behavior in this._oldCollection) { - IBehavior behaviorItem = (IBehavior)item; - if (behaviorItem.AssociatedObject != null) + if (behavior.AssociatedObject != null) { - behaviorItem.Detach(); + behavior.Detach(); } } - this.AssociatedObject = null; this._oldCollection.Clear(); - } - private void BehaviorCollection_VectorChanged(IObservableVector sender, IVectorChangedEventArgs eventArgs) - { - if (eventArgs.CollectionChange == CollectionChange.Reset) + foreach (DependencyObject newItem in this) { - foreach (IBehavior behavior in this._oldCollection) - { - if (behavior.AssociatedObject != null) - { - behavior.Detach(); - } - } - - this._oldCollection.Clear(); - - foreach (DependencyObject newItem in this) - { - this._oldCollection.Add(this.VerifiedAttach(newItem)); - } + this._oldCollection.Add(this.VerifiedAttach(newItem)); + } #if DEBUG - this.VerifyOldCollectionIntegrity(); + this.VerifyOldCollectionIntegrity(); #endif - return; - } + return; + } - int eventIndex = (int)eventArgs.Index; - DependencyObject changedItem = this[eventIndex]; + int eventIndex = (int)eventArgs.Index; + DependencyObject changedItem = this[eventIndex]; - switch (eventArgs.CollectionChange) - { - case CollectionChange.ItemInserted: - this._oldCollection.Insert(eventIndex, this.VerifiedAttach(changedItem)); + switch (eventArgs.CollectionChange) + { + case CollectionChange.ItemInserted: + this._oldCollection.Insert(eventIndex, this.VerifiedAttach(changedItem)); - break; + break; - case CollectionChange.ItemChanged: - IBehavior oldItem = this._oldCollection[eventIndex]; - if (oldItem.AssociatedObject != null) - { - oldItem.Detach(); - } + case CollectionChange.ItemChanged: + IBehavior oldItem = this._oldCollection[eventIndex]; + if (oldItem.AssociatedObject != null) + { + oldItem.Detach(); + } - this._oldCollection[eventIndex] = this.VerifiedAttach(changedItem); + this._oldCollection[eventIndex] = this.VerifiedAttach(changedItem); - break; + break; - case CollectionChange.ItemRemoved: - oldItem = this._oldCollection[eventIndex]; - if (oldItem.AssociatedObject != null) - { - oldItem.Detach(); - } + case CollectionChange.ItemRemoved: + oldItem = this._oldCollection[eventIndex]; + if (oldItem.AssociatedObject != null) + { + oldItem.Detach(); + } - this._oldCollection.RemoveAt(eventIndex); - break; + this._oldCollection.RemoveAt(eventIndex); + break; - default: - Debug.Assert(false, "Unsupported collection operation attempted."); - break; - } + default: + Debug.Assert(false, "Unsupported collection operation attempted."); + break; + } #if DEBUG - this.VerifyOldCollectionIntegrity(); + this.VerifyOldCollectionIntegrity(); #endif - } + } - private IBehavior VerifiedAttach(DependencyObject item) + private IBehavior VerifiedAttach(DependencyObject item) + { + IBehavior behavior = item as IBehavior; + if (behavior == null) { - IBehavior behavior = item as IBehavior; - if (behavior == null) - { - throw new InvalidOperationException(ResourceHelper.GetString("NonBehaviorAddedToBehaviorCollectionExceptionMessage")); - } - - if (this._oldCollection.Contains(behavior)) - { - throw new InvalidOperationException(ResourceHelper.GetString("DuplicateBehaviorInCollectionExceptionMessage")); - } + throw new InvalidOperationException(ResourceHelper.GetString("NonBehaviorAddedToBehaviorCollectionExceptionMessage")); + } - if (this.AssociatedObject != null) - { - behavior.Attach(this.AssociatedObject); - } + if (this._oldCollection.Contains(behavior)) + { + throw new InvalidOperationException(ResourceHelper.GetString("DuplicateBehaviorInCollectionExceptionMessage")); + } - return behavior; + if (this.AssociatedObject != null) + { + behavior.Attach(this.AssociatedObject); } + return behavior; + } + #if DEBUG - [Conditional("DEBUG")] - private void VerifyOldCollectionIntegrity() + [Conditional("DEBUG")] + private void VerifyOldCollectionIntegrity() + { + bool isValid = (this.Count == this._oldCollection.Count); + if (isValid) { - bool isValid = (this.Count == this._oldCollection.Count); - if (isValid) + for (int i = 0; i < this.Count; i++) { - for (int i = 0; i < this.Count; i++) + if (!ReferenceEquals(this[i], this._oldCollection[i])) { - if (!ReferenceEquals(this[i], this._oldCollection[i])) - { - isValid = false; - break; - } + isValid = false; + break; } } - - Debug.Assert(isValid, "Referential integrity of the collection has been compromised."); } -#endif + + Debug.Assert(isValid, "Referential integrity of the collection has been compromised."); } +#endif } diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/BehaviorOfT.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/BehaviorOfT.cs index a8f96df..4d482b7 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/BehaviorOfT.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/BehaviorOfT.cs @@ -9,40 +9,39 @@ using Windows.UI.Xaml; #endif -namespace Microsoft.Xaml.Interactivity +namespace Microsoft.Xaml.Interactivity; + +/// +/// A base class for behaviors making them code compatible with older frameworks, +/// and allow for typed associtated objects. +/// +/// The object type to attach to +public abstract class Behavior : Behavior where T : DependencyObject { /// - /// A base class for behaviors making them code compatible with older frameworks, - /// and allow for typed associtated objects. + /// Gets the object to which this behavior is attached. /// - /// The object type to attach to - public abstract class Behavior : Behavior where T : DependencyObject + public new T AssociatedObject { - /// - /// Gets the object to which this behavior is attached. - /// - public new T AssociatedObject - { - get { return base.AssociatedObject as T; } - } + get { return base.AssociatedObject as T; } + } - /// - /// Called after the behavior is attached to the . - /// - /// - /// Override this to hook up functionality to the - /// - protected override void OnAttached() - { - base.OnAttached(); + /// + /// Called after the behavior is attached to the . + /// + /// + /// Override this to hook up functionality to the + /// + protected override void OnAttached() + { + base.OnAttached(); - if (this.AssociatedObject == null) - { - string actualType = base.AssociatedObject.GetType().FullName; - string expectedType = typeof (T).FullName; - string message = string.Format(ResourceHelper.GetString("InvalidAssociatedObjectExceptionMessage"), actualType, expectedType); - throw new InvalidOperationException(message); - } + if (this.AssociatedObject == null) + { + string actualType = base.AssociatedObject.GetType().FullName; + string expectedType = typeof (T).FullName; + string message = string.Format(ResourceHelper.GetString("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 9911044..620662b 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/CallMethodAction.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/CallMethodAction.cs @@ -14,276 +14,275 @@ using Windows.UI.Xaml; #endif -namespace Microsoft.Xaml.Interactivity +namespace Microsoft.Xaml.Interactivity; + +/// +/// An action that calls a method on a specified object when invoked. +/// +#if NET8_0_OR_GREATER +[RequiresUnreferencedCode("This action is not trim-safe.")] +#endif +public sealed class CallMethodAction : DependencyObject, IAction { /// - /// An action that calls a method on a specified object when invoked. + /// Identifies the dependency property. /// -#if NET8_0_OR_GREATER - [RequiresUnreferencedCode("This action is not trim-safe.")] -#endif - public sealed class CallMethodAction : DependencyObject, IAction + [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] + public static readonly DependencyProperty MethodNameProperty = DependencyProperty.Register( + "MethodName", + typeof(string), + typeof(CallMethodAction), + new PropertyMetadata(null, new PropertyChangedCallback(CallMethodAction.OnMethodNameChanged))); + + /// + /// Identifies the dependency property. + /// + [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] + public static readonly DependencyProperty TargetObjectProperty = DependencyProperty.Register( + "TargetObject", + typeof(object), + typeof(CallMethodAction), + new PropertyMetadata(null, new PropertyChangedCallback(CallMethodAction.OnTargetObjectChanged))); + + private Type _targetObjectType; + private List _methodDescriptors = new List(); + private MethodDescriptor _cachedMethodDescriptor; + + /// + /// Gets or sets the name of the method to invoke. This is a dependency property. + /// + public string MethodName { - /// - /// Identifies the dependency property. - /// - [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] - public static readonly DependencyProperty MethodNameProperty = DependencyProperty.Register( - "MethodName", - typeof(string), - typeof(CallMethodAction), - new PropertyMetadata(null, new PropertyChangedCallback(CallMethodAction.OnMethodNameChanged))); - - /// - /// Identifies the dependency property. - /// - [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] - public static readonly DependencyProperty TargetObjectProperty = DependencyProperty.Register( - "TargetObject", - typeof(object), - typeof(CallMethodAction), - new PropertyMetadata(null, new PropertyChangedCallback(CallMethodAction.OnTargetObjectChanged))); - - private Type _targetObjectType; - private List _methodDescriptors = new List(); - private MethodDescriptor _cachedMethodDescriptor; - - /// - /// Gets or sets the name of the method to invoke. This is a dependency property. - /// - public string MethodName + get { - get - { - return (string)this.GetValue(CallMethodAction.MethodNameProperty); - } - - set - { - this.SetValue(CallMethodAction.MethodNameProperty, value); - } + return (string)this.GetValue(CallMethodAction.MethodNameProperty); } - /// - /// Gets or sets the object that exposes the method of interest. This is a dependency property. - /// - public object TargetObject + set { - get - { - return this.GetValue(CallMethodAction.TargetObjectProperty); - } - - set - { - this.SetValue(CallMethodAction.TargetObjectProperty, value); - } + this.SetValue(CallMethodAction.MethodNameProperty, value); } + } - /// - /// Executes the action. - /// - /// The that is passed to the action by the behavior. Generally this is or a target object. - /// The value of this parameter is determined by the caller. - /// True if the method is called; else false. - public object Execute(object sender, object parameter) + /// + /// Gets or sets the object that exposes the method of interest. This is a dependency property. + /// + public object TargetObject + { + get { - object target; - if (this.ReadLocalValue(CallMethodAction.TargetObjectProperty) != DependencyProperty.UnsetValue) - { - target = this.TargetObject; - } - else - { - target = sender; - } + return this.GetValue(CallMethodAction.TargetObjectProperty); + } - if (target == null || string.IsNullOrEmpty(this.MethodName)) - { - return false; - } + set + { + this.SetValue(CallMethodAction.TargetObjectProperty, value); + } + } - this.UpdateTargetType(target.GetType()); + /// + /// Executes the action. + /// + /// The that is passed to the action by the behavior. Generally this is or a target object. + /// The value of this parameter is determined by the caller. + /// True if the method is called; else false. + public object Execute(object sender, object parameter) + { + object target; + if (this.ReadLocalValue(CallMethodAction.TargetObjectProperty) != DependencyProperty.UnsetValue) + { + target = this.TargetObject; + } + else + { + target = sender; + } - MethodDescriptor methodDescriptor = this.FindBestMethod(parameter); - if (methodDescriptor == null) - { - if (this.TargetObject != null) - { - throw new ArgumentException(string.Format( - CultureInfo.CurrentCulture, - ResourceHelper.CallMethodActionValidMethodNotFoundExceptionMessage, - this.MethodName, - this._targetObjectType)); - } + if (target == null || string.IsNullOrEmpty(this.MethodName)) + { + return false; + } - return false; - } + this.UpdateTargetType(target.GetType()); - ParameterInfo[] parameters = methodDescriptor.Parameters; - if (parameters.Length == 0) - { - methodDescriptor.MethodInfo.Invoke(target, parameters: null); - return true; - } - else if (parameters.Length == 2) + MethodDescriptor methodDescriptor = this.FindBestMethod(parameter); + if (methodDescriptor == null) + { + if (this.TargetObject != null) { - methodDescriptor.MethodInfo.Invoke(target, new object[] { target, parameter }); - return true; + throw new ArgumentException(string.Format( + CultureInfo.CurrentCulture, + ResourceHelper.CallMethodActionValidMethodNotFoundExceptionMessage, + this.MethodName, + this._targetObjectType)); } return false; } - private MethodDescriptor FindBestMethod(object parameter) + ParameterInfo[] parameters = methodDescriptor.Parameters; + if (parameters.Length == 0) { - TypeInfo parameterTypeInfo = parameter == null ? null : parameter.GetType().GetTypeInfo(); + methodDescriptor.MethodInfo.Invoke(target, parameters: null); + return true; + } + else if (parameters.Length == 2) + { + methodDescriptor.MethodInfo.Invoke(target, new object[] { target, parameter }); + return true; + } - if (parameterTypeInfo == null) - { - return this._cachedMethodDescriptor; - } + return false; + } - MethodDescriptor mostDerivedMethod = null; + private MethodDescriptor FindBestMethod(object parameter) + { + TypeInfo parameterTypeInfo = parameter == null ? null : parameter.GetType().GetTypeInfo(); - // Loop over the methods looking for the one whose type is closest to the type of the given parameter. - foreach (MethodDescriptor currentMethod in this._methodDescriptors) - { - TypeInfo currentTypeInfo = currentMethod.SecondParameterTypeInfo; + if (parameterTypeInfo == null) + { + return this._cachedMethodDescriptor; + } + + MethodDescriptor mostDerivedMethod = null; + + // Loop over the methods looking for the one whose type is closest to the type of the given parameter. + foreach (MethodDescriptor currentMethod in this._methodDescriptors) + { + TypeInfo currentTypeInfo = currentMethod.SecondParameterTypeInfo; - if (currentTypeInfo.IsAssignableFrom(parameterTypeInfo)) + if (currentTypeInfo.IsAssignableFrom(parameterTypeInfo)) + { + if (mostDerivedMethod == null || !currentTypeInfo.IsAssignableFrom(mostDerivedMethod.SecondParameterTypeInfo)) { - if (mostDerivedMethod == null || !currentTypeInfo.IsAssignableFrom(mostDerivedMethod.SecondParameterTypeInfo)) - { - mostDerivedMethod = currentMethod; - } + mostDerivedMethod = currentMethod; } } - - return mostDerivedMethod ?? this._cachedMethodDescriptor; } - private void UpdateTargetType(Type newTargetType) + return mostDerivedMethod ?? this._cachedMethodDescriptor; + } + + private void UpdateTargetType(Type newTargetType) + { + if (newTargetType == this._targetObjectType) { - if (newTargetType == this._targetObjectType) - { - return; - } + return; + } - this._targetObjectType = newTargetType; + this._targetObjectType = newTargetType; - this.UpdateMethodDescriptors(); - } + this.UpdateMethodDescriptors(); + } - private void UpdateMethodDescriptors() - { - this._methodDescriptors.Clear(); - this._cachedMethodDescriptor = null; + private void UpdateMethodDescriptors() + { + this._methodDescriptors.Clear(); + this._cachedMethodDescriptor = null; - if (string.IsNullOrEmpty(this.MethodName) || this._targetObjectType == null) - { - return; - } + if (string.IsNullOrEmpty(this.MethodName) || this._targetObjectType == null) + { + return; + } - // Find all public methods that match the given name and have either no parameters, - // or two parameters where the first is of type Object. - foreach (MethodInfo method in this._targetObjectType.GetRuntimeMethods()) + // Find all public methods that match the given name and have either no parameters, + // or two parameters where the first is of type Object. + foreach (MethodInfo method in this._targetObjectType.GetRuntimeMethods()) + { + if (string.Equals(method.Name, this.MethodName, StringComparison.Ordinal) + && method.ReturnType == typeof(void) + && method.IsPublic) { - if (string.Equals(method.Name, this.MethodName, StringComparison.Ordinal) - && method.ReturnType == typeof(void) - && method.IsPublic) + ParameterInfo[] parameters = method.GetParameters(); + if (parameters.Length == 0) { - ParameterInfo[] parameters = method.GetParameters(); - if (parameters.Length == 0) - { - // There can be only one parameterless method of the given name. - this._cachedMethodDescriptor = new MethodDescriptor(method, parameters); - } - else if (parameters.Length == 2 && parameters[0].ParameterType == typeof(object)) - { - this._methodDescriptors.Add(new MethodDescriptor(method, parameters)); - } + // There can be only one parameterless method of the given name. + this._cachedMethodDescriptor = new MethodDescriptor(method, parameters); + } + else if (parameters.Length == 2 && parameters[0].ParameterType == typeof(object)) + { + this._methodDescriptors.Add(new MethodDescriptor(method, parameters)); } } + } - // We didn't find a parameterless method, so we want to find a method that accepts null - // as a second parameter, but if we have more than one of these it is ambigious which - // we should call, so we do nothing. - if (this._cachedMethodDescriptor == null) + // We didn't find a parameterless method, so we want to find a method that accepts null + // as a second parameter, but if we have more than one of these it is ambigious which + // we should call, so we do nothing. + if (this._cachedMethodDescriptor == null) + { + foreach (MethodDescriptor method in this._methodDescriptors) { - foreach (MethodDescriptor method in this._methodDescriptors) + TypeInfo typeInfo = method.SecondParameterTypeInfo; + if (!typeInfo.IsValueType || (typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == typeof(Nullable<>))) { - TypeInfo typeInfo = method.SecondParameterTypeInfo; - if (!typeInfo.IsValueType || (typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == typeof(Nullable<>))) + if (this._cachedMethodDescriptor != null) + { + this._cachedMethodDescriptor = null; + return; + } + else { - if (this._cachedMethodDescriptor != null) - { - this._cachedMethodDescriptor = null; - return; - } - else - { - this._cachedMethodDescriptor = method; - } + this._cachedMethodDescriptor = method; } } } } + } + + private static void OnMethodNameChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args) + { + CallMethodAction callMethodAction = (CallMethodAction)sender; + callMethodAction.UpdateMethodDescriptors(); + } + + private static void OnTargetObjectChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args) + { + CallMethodAction callMethodAction = (CallMethodAction)sender; + + Type newType = args.NewValue != null ? args.NewValue.GetType() : null; + callMethodAction.UpdateTargetType(newType); + } - private static void OnMethodNameChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args) + [DebuggerDisplay("{MethodInfo}")] + private class MethodDescriptor + { + public MethodDescriptor(MethodInfo methodInfo, ParameterInfo[] methodParameters) { - CallMethodAction callMethodAction = (CallMethodAction)sender; - callMethodAction.UpdateMethodDescriptors(); + this.MethodInfo = methodInfo; + this.Parameters = methodParameters; } - private static void OnTargetObjectChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args) + public MethodInfo MethodInfo { - CallMethodAction callMethodAction = (CallMethodAction)sender; - - Type newType = args.NewValue != null ? args.NewValue.GetType() : null; - callMethodAction.UpdateTargetType(newType); + get; + private set; } - [DebuggerDisplay("{MethodInfo}")] - private class MethodDescriptor + public ParameterInfo[] Parameters { - public MethodDescriptor(MethodInfo methodInfo, ParameterInfo[] methodParameters) - { - this.MethodInfo = methodInfo; - this.Parameters = methodParameters; - } - - public MethodInfo MethodInfo - { - get; - private set; - } + get; + private set; + } - public ParameterInfo[] Parameters + public int ParameterCount + { + get { - get; - private set; + return this.Parameters.Length; } + } - public int ParameterCount + public TypeInfo SecondParameterTypeInfo + { + get { - get + if (this.ParameterCount < 2) { - return this.Parameters.Length; + return null; } - } - public TypeInfo SecondParameterTypeInfo - { - get - { - if (this.ParameterCount < 2) - { - return null; - } - - return this.Parameters[1].ParameterType.GetTypeInfo(); - } + return this.Parameters[1].ParameterType.GetTypeInfo(); } } } diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ChangePropertyAction.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ChangePropertyAction.cs index dd905e3..9de5e71 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ChangePropertyAction.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ChangePropertyAction.cs @@ -12,193 +12,192 @@ using Windows.UI.Xaml; #endif -namespace Microsoft.Xaml.Interactivity +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.")] +#endif +public sealed class ChangePropertyAction : DependencyObject, IAction { /// - /// An action that will change a specified property to a specified value when invoked. + /// Identifies the dependency property. /// -#if NET8_0_OR_GREATER - [RequiresUnreferencedCode("This action is not trim-safe.")] -#endif - public sealed class ChangePropertyAction : DependencyObject, IAction + [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] + public static readonly DependencyProperty PropertyNameProperty = DependencyProperty.Register( + "PropertyName", + typeof(PropertyPath), + typeof(ChangePropertyAction), + new PropertyMetadata(null)); + + /// + /// Identifies the dependency property. + /// + [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] + public static readonly DependencyProperty TargetObjectProperty = DependencyProperty.Register( + "TargetObject", + typeof(object), + typeof(ChangePropertyAction), + new PropertyMetadata(null)); + + /// + /// Identifies the dependency property. + /// + [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] + public static readonly DependencyProperty ValueProperty = DependencyProperty.Register( + "Value", + typeof(object), + typeof(ChangePropertyAction), + new PropertyMetadata(null)); + + /// + /// Gets or sets the name of the property to change. This is a dependency property. + /// + public PropertyPath PropertyName { - /// - /// Identifies the dependency property. - /// - [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] - public static readonly DependencyProperty PropertyNameProperty = DependencyProperty.Register( - "PropertyName", - typeof(PropertyPath), - typeof(ChangePropertyAction), - new PropertyMetadata(null)); - - /// - /// Identifies the dependency property. - /// - [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] - public static readonly DependencyProperty TargetObjectProperty = DependencyProperty.Register( - "TargetObject", - typeof(object), - typeof(ChangePropertyAction), - new PropertyMetadata(null)); - - /// - /// Identifies the dependency property. - /// - [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] - public static readonly DependencyProperty ValueProperty = DependencyProperty.Register( - "Value", - typeof(object), - typeof(ChangePropertyAction), - new PropertyMetadata(null)); - - /// - /// Gets or sets the name of the property to change. This is a dependency property. - /// - public PropertyPath PropertyName + get { - get - { - return (PropertyPath)this.GetValue(ChangePropertyAction.PropertyNameProperty); - } - set - { - this.SetValue(ChangePropertyAction.PropertyNameProperty, value); - } + return (PropertyPath)this.GetValue(ChangePropertyAction.PropertyNameProperty); } - - /// - /// Gets or sets the value to set. This is a dependency property. - /// - [SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods")] - public object Value + set { - get - { - return this.GetValue(ChangePropertyAction.ValueProperty); - } - set - { - this.SetValue(ChangePropertyAction.ValueProperty, value); - } + this.SetValue(ChangePropertyAction.PropertyNameProperty, 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 object TargetObject + /// + /// Gets or sets the value to set. This is a dependency property. + /// + [SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods")] + public object Value + { + get { - get - { - return (object)this.GetValue(ChangePropertyAction.TargetObjectProperty); - } - set - { - this.SetValue(ChangePropertyAction.TargetObjectProperty, value); - } + return this.GetValue(ChangePropertyAction.ValueProperty); } - - /// - /// Executes the action. - /// - /// The that is passed to the action by the behavior. Generally this is or a target object. - /// The value of this parameter is determined by the caller. - /// True if updating the property value succeeds; else false. - public object Execute(object sender, object parameter) + set { - object targetObject; - if (this.ReadLocalValue(ChangePropertyAction.TargetObjectProperty) != DependencyProperty.UnsetValue) - { - targetObject = this.TargetObject; - } - else - { - targetObject = sender; - } + this.SetValue(ChangePropertyAction.ValueProperty, value); + } + } - if (targetObject == null || this.PropertyName == null) - { - return false; - } + /// + /// 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 object TargetObject + { + get + { + return (object)this.GetValue(ChangePropertyAction.TargetObjectProperty); + } + set + { + this.SetValue(ChangePropertyAction.TargetObjectProperty, value); + } + } - this.UpdatePropertyValue(targetObject); - return true; + /// + /// Executes the action. + /// + /// The that is passed to the action by the behavior. Generally this is or a target object. + /// The value of this parameter is determined by the caller. + /// True if updating the property value succeeds; else false. + public object Execute(object sender, object parameter) + { + object targetObject; + if (this.ReadLocalValue(ChangePropertyAction.TargetObjectProperty) != DependencyProperty.UnsetValue) + { + targetObject = this.TargetObject; + } + else + { + targetObject = sender; } - private void UpdatePropertyValue(object targetObject) + if (targetObject == null || this.PropertyName == null) { - Type targetType = targetObject.GetType(); - PropertyInfo propertyInfo = targetType.GetRuntimeProperty(this.PropertyName.Path); - this.ValidateProperty(targetType.Name, propertyInfo); + return false; + } - Exception innerException = null; - try + this.UpdatePropertyValue(targetObject); + return true; + } + + private void UpdatePropertyValue(object targetObject) + { + Type targetType = targetObject.GetType(); + PropertyInfo propertyInfo = targetType.GetRuntimeProperty(this.PropertyName.Path); + this.ValidateProperty(targetType.Name, propertyInfo); + + Exception innerException = null; + try + { + object result = null; + string valueAsString = null; + Type propertyType = propertyInfo.PropertyType; + TypeInfo propertyTypeInfo = propertyType.GetTypeInfo(); + if (this.Value == null) { - object result = null; - string valueAsString = null; - Type propertyType = propertyInfo.PropertyType; - TypeInfo propertyTypeInfo = propertyType.GetTypeInfo(); - if (this.Value == null) - { - // The result can be null if the type is generic (nullable), or the default value of the type in question - result = propertyTypeInfo.IsValueType ? Activator.CreateInstance(propertyType) : null; - } - else if (propertyTypeInfo.IsAssignableFrom(this.Value.GetType().GetTypeInfo())) - { - result = this.Value; - } - else - { - valueAsString = this.Value.ToString(); - result = propertyTypeInfo.IsEnum ? Enum.Parse(propertyType, valueAsString, false) : - TypeConverterHelper.Convert(valueAsString, propertyType.FullName); - } - - propertyInfo.SetValue(targetObject, result, new object[0]); + // The result can be null if the type is generic (nullable), or the default value of the type in question + result = propertyTypeInfo.IsValueType ? Activator.CreateInstance(propertyType) : null; } - catch (FormatException e) + else if (propertyTypeInfo.IsAssignableFrom(this.Value.GetType().GetTypeInfo())) { - innerException = e; + result = this.Value; } - catch (ArgumentException e) + else { - innerException = e; + valueAsString = this.Value.ToString(); + result = propertyTypeInfo.IsEnum ? Enum.Parse(propertyType, valueAsString, false) : + TypeConverterHelper.Convert(valueAsString, propertyType.FullName); } - if (innerException != null) - { - throw new ArgumentException(string.Format( - CultureInfo.CurrentCulture, - ResourceHelper.ChangePropertyActionCannotSetValueExceptionMessage, - this.Value != null ? this.Value.GetType().Name : "null", - this.PropertyName, - propertyInfo.PropertyType.Name), - innerException); - } + propertyInfo.SetValue(targetObject, result, new object[0]); + } + catch (FormatException e) + { + innerException = e; + } + catch (ArgumentException e) + { + innerException = e; } - /// - /// Ensures the property is not null and can be written to. - /// - private void ValidateProperty(string targetTypeName, PropertyInfo propertyInfo) + if (innerException != null) { - if (propertyInfo == null) - { - throw new ArgumentException(string.Format( - CultureInfo.CurrentCulture, - ResourceHelper.ChangePropertyActionCannotFindPropertyNameExceptionMessage, - this.PropertyName, - targetTypeName)); - } - else if (!propertyInfo.CanWrite) - { - throw new ArgumentException(string.Format( - CultureInfo.CurrentCulture, - ResourceHelper.ChangePropertyActionPropertyIsReadOnlyExceptionMessage, - this.PropertyName, - targetTypeName)); - } + throw new ArgumentException(string.Format( + CultureInfo.CurrentCulture, + ResourceHelper.ChangePropertyActionCannotSetValueExceptionMessage, + this.Value != null ? this.Value.GetType().Name : "null", + this.PropertyName, + propertyInfo.PropertyType.Name), + innerException); + } + } + + /// + /// Ensures the property is not null and can be written to. + /// + private void ValidateProperty(string targetTypeName, PropertyInfo propertyInfo) + { + if (propertyInfo == null) + { + throw new ArgumentException(string.Format( + CultureInfo.CurrentCulture, + ResourceHelper.ChangePropertyActionCannotFindPropertyNameExceptionMessage, + this.PropertyName, + targetTypeName)); + } + else if (!propertyInfo.CanWrite) + { + throw new ArgumentException(string.Format( + CultureInfo.CurrentCulture, + ResourceHelper.ChangePropertyActionPropertyIsReadOnlyExceptionMessage, + this.PropertyName, + targetTypeName)); } } } diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ComparisonConditionType.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ComparisonConditionType.cs index 43712a2..d5d50cb 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ComparisonConditionType.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ComparisonConditionType.cs @@ -1,36 +1,35 @@ // 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 +namespace Microsoft.Xaml.Interactivity; + +/// +/// Represents one ternary condition. +/// +public enum ComparisonConditionType { /// - /// Represents one ternary condition. + /// Specifies an equal condition. + /// + Equal, + /// + /// Specifies a not equal condition. + /// + NotEqual, + /// + /// Specifies a less than condition. + /// + LessThan, + /// + /// Specifies a less than or equal condition. + /// + LessThanOrEqual, + /// + /// Specifies a greater than condition. + /// + GreaterThan, + /// + /// Specifies a greater than or equal condition. /// - public enum ComparisonConditionType - { - /// - /// Specifies an equal condition. - /// - Equal, - /// - /// Specifies a not equal condition. - /// - NotEqual, - /// - /// Specifies a less than condition. - /// - LessThan, - /// - /// Specifies a less than or equal condition. - /// - LessThanOrEqual, - /// - /// Specifies a greater than condition. - /// - GreaterThan, - /// - /// Specifies a greater than or equal condition. - /// - GreaterThanOrEqual - } + GreaterThanOrEqual } diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/DataBindingHelper.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/DataBindingHelper.cs index 2dd72fb..93dde39 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/DataBindingHelper.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/DataBindingHelper.cs @@ -16,76 +16,75 @@ using Windows.UI.Xaml.Data; #endif -namespace Microsoft.Xaml.Interactivity +namespace Microsoft.Xaml.Interactivity; + +internal static class DataBindingHelper { - internal static class DataBindingHelper - { - private static readonly Dictionary> DependenciesPropertyCache = new Dictionary>(); + private static readonly Dictionary> DependenciesPropertyCache = new Dictionary>(); - /// - /// Ensures that all binding expression on actions are up to date. - /// - /// - /// DataTriggerBehavior fires during data binding phase. Since the ActionCollection is a child of the behavior, - /// 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. - /// + /// + /// Ensures that all binding expression on actions are up to date. + /// + /// + /// DataTriggerBehavior fires during data binding phase. Since the ActionCollection is a child of the behavior, + /// 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 - [RequiresUnreferencedCode("This method accesses all fields of input action objects.")] + [RequiresUnreferencedCode("This method accesses all fields of input action objects.")] #endif - public static void RefreshDataBindingsOnActions(ActionCollection actions) + public static void RefreshDataBindingsOnActions(ActionCollection actions) + { + foreach (DependencyObject action in actions) { - foreach (DependencyObject action in actions) + foreach (DependencyProperty property in DataBindingHelper.GetDependencyProperties(action.GetType())) { - foreach (DependencyProperty property in DataBindingHelper.GetDependencyProperties(action.GetType())) - { - DataBindingHelper.RefreshBinding(action, property); - } + DataBindingHelper.RefreshBinding(action, property); } } + } - private static IEnumerable GetDependencyProperties( + private static IEnumerable GetDependencyProperties( #if NET8_0_OR_GREATER - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] #endif - Type type) + Type type) + { + List propertyList = null; + + if (!DataBindingHelper.DependenciesPropertyCache.TryGetValue(type, out propertyList)) { - List propertyList = null; + propertyList = new List(); - if (!DataBindingHelper.DependenciesPropertyCache.TryGetValue(type, out propertyList)) + while (type != null && type != typeof(DependencyObject)) { - propertyList = new List(); - - while (type != null && type != typeof(DependencyObject)) + foreach (FieldInfo fieldInfo in type.GetRuntimeFields()) { - foreach (FieldInfo fieldInfo in type.GetRuntimeFields()) + if (fieldInfo.IsPublic && fieldInfo.FieldType == typeof(DependencyProperty)) { - if (fieldInfo.IsPublic && fieldInfo.FieldType == typeof(DependencyProperty)) + DependencyProperty property = fieldInfo.GetValue(null) as DependencyProperty; + if (property != null) { - DependencyProperty property = fieldInfo.GetValue(null) as DependencyProperty; - if (property != null) - { - propertyList.Add(property); - } + propertyList.Add(property); } } - - type = type.GetTypeInfo().BaseType; } - DataBindingHelper.DependenciesPropertyCache[type] = propertyList; + type = type.GetTypeInfo().BaseType; } - return propertyList; + DataBindingHelper.DependenciesPropertyCache[type] = propertyList; } - private static void RefreshBinding(DependencyObject target, DependencyProperty property) + return propertyList; + } + + private static void RefreshBinding(DependencyObject target, DependencyProperty property) + { + BindingExpression binding = target.ReadLocalValue(property) as BindingExpression; + if (binding != null && binding.ParentBinding != null) { - BindingExpression binding = target.ReadLocalValue(property) as BindingExpression; - if (binding != null && binding.ParentBinding != null) - { - BindingOperations.SetBinding(target, property, binding.ParentBinding); - } + BindingOperations.SetBinding(target, property, binding.ParentBinding); } } } diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/DataTriggerBehavior.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/DataTriggerBehavior.cs index 5158939..90c2b89 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/DataTriggerBehavior.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/DataTriggerBehavior.cs @@ -11,215 +11,214 @@ using Windows.UI.Xaml; #endif -namespace Microsoft.Xaml.Interactivity +namespace Microsoft.Xaml.Interactivity; + +/// +/// A behavior that performs actions when the bound data meets a specified condition. +/// +#if NET8_0_OR_GREATER +[RequiresUnreferencedCode("This behavior is not trim-safe.")] +#endif +public sealed class DataTriggerBehavior : Trigger { /// - /// A behavior that performs actions when the bound data meets a specified condition. + /// Identifies the dependency property. /// -#if NET8_0_OR_GREATER - [RequiresUnreferencedCode("This behavior is not trim-safe.")] -#endif - public sealed class DataTriggerBehavior : Trigger + [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] + public static readonly DependencyProperty BindingProperty = DependencyProperty.Register( + "Binding", + typeof(object), + typeof(DataTriggerBehavior), + new PropertyMetadata(null, new PropertyChangedCallback(DataTriggerBehavior.OnValueChanged))); + + /// + /// Identifies the dependency property. + /// + [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] + public static readonly DependencyProperty ComparisonConditionProperty = DependencyProperty.Register( + "ComparisonCondition", + typeof(ComparisonConditionType), + typeof(DataTriggerBehavior), + new PropertyMetadata(ComparisonConditionType.Equal, + new PropertyChangedCallback(DataTriggerBehavior.OnValueChanged))); + + /// + /// Identifies the dependency property. + /// + [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] + public static readonly DependencyProperty ValueProperty = DependencyProperty.Register( + "Value", + typeof(object), + typeof(DataTriggerBehavior), + new PropertyMetadata(null, new PropertyChangedCallback(DataTriggerBehavior.OnValueChanged))); + + /// + /// Gets or sets the bound object that the will listen to. This is a dependency property. + /// + public object Binding { - /// - /// Identifies the dependency property. - /// - [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] - public static readonly DependencyProperty BindingProperty = DependencyProperty.Register( - "Binding", - typeof(object), - typeof(DataTriggerBehavior), - new PropertyMetadata(null, new PropertyChangedCallback(DataTriggerBehavior.OnValueChanged))); - - /// - /// Identifies the dependency property. - /// - [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] - public static readonly DependencyProperty ComparisonConditionProperty = DependencyProperty.Register( - "ComparisonCondition", - typeof(ComparisonConditionType), - typeof(DataTriggerBehavior), - new PropertyMetadata(ComparisonConditionType.Equal, - new PropertyChangedCallback(DataTriggerBehavior.OnValueChanged))); - - /// - /// Identifies the dependency property. - /// - [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] - public static readonly DependencyProperty ValueProperty = DependencyProperty.Register( - "Value", - typeof(object), - typeof(DataTriggerBehavior), - new PropertyMetadata(null, new PropertyChangedCallback(DataTriggerBehavior.OnValueChanged))); - - /// - /// Gets or sets the bound object that the will listen to. This is a dependency property. - /// - public object Binding - { - get - { - return (object)this.GetValue(DataTriggerBehavior.BindingProperty); - } - set - { - this.SetValue(DataTriggerBehavior.BindingProperty, value); - } - } - - /// - /// Gets or sets the type of comparison to be performed between and . This is a dependency property. - /// - public ComparisonConditionType ComparisonCondition - { - get - { - return (ComparisonConditionType)this.GetValue(DataTriggerBehavior.ComparisonConditionProperty); - } - set - { - this.SetValue(DataTriggerBehavior.ComparisonConditionProperty, value); - } - } - - /// - /// Gets or sets the value to be compared with the value of . This is a dependency property. - /// - [SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods")] - public object Value - { - get - { - return (object)this.GetValue(DataTriggerBehavior.ValueProperty); - } - set - { - this.SetValue(DataTriggerBehavior.ValueProperty, value); - } - } - - private static bool Compare(object leftOperand, ComparisonConditionType operatorType, object rightOperand) - { - if (leftOperand != null && rightOperand != null) - { - rightOperand = TypeConverterHelper.Convert(rightOperand.ToString(), leftOperand.GetType().FullName); - } - - IComparable leftComparableOperand = leftOperand as IComparable; - IComparable rightComparableOperand = rightOperand as IComparable; - if ((leftComparableOperand != null) && (rightComparableOperand != null)) - { - return DataTriggerBehavior.EvaluateComparable(leftComparableOperand, operatorType, rightComparableOperand); - } - - switch (operatorType) - { - case ComparisonConditionType.Equal: - return object.Equals(leftOperand, rightOperand); - - case ComparisonConditionType.NotEqual: - return !object.Equals(leftOperand, rightOperand); - - case ComparisonConditionType.LessThan: - case ComparisonConditionType.LessThanOrEqual: - case ComparisonConditionType.GreaterThan: - case ComparisonConditionType.GreaterThanOrEqual: - { - if (leftComparableOperand == null && rightComparableOperand == null) - { - throw new ArgumentException(string.Format( - CultureInfo.CurrentCulture, - ResourceHelper.InvalidOperands, - leftOperand != null ? leftOperand.GetType().Name : "null", - rightOperand != null ? rightOperand.GetType().Name : "null", - operatorType.ToString())); - } - else if (leftComparableOperand == null) - { - throw new ArgumentException(string.Format( - CultureInfo.CurrentCulture, - ResourceHelper.InvalidLeftOperand, - leftOperand != null ? leftOperand.GetType().Name : "null", - operatorType.ToString())); - } - else - { - throw new ArgumentException(string.Format( - CultureInfo.CurrentCulture, - ResourceHelper.InvalidRightOperand, - rightOperand != null ? rightOperand.GetType().Name : "null", - operatorType.ToString())); - } - } - } + get + { + return (object)this.GetValue(DataTriggerBehavior.BindingProperty); + } + set + { + this.SetValue(DataTriggerBehavior.BindingProperty, value); + } + } + + /// + /// Gets or sets the type of comparison to be performed between and . This is a dependency property. + /// + public ComparisonConditionType ComparisonCondition + { + get + { + return (ComparisonConditionType)this.GetValue(DataTriggerBehavior.ComparisonConditionProperty); + } + set + { + this.SetValue(DataTriggerBehavior.ComparisonConditionProperty, value); + } + } + + /// + /// Gets or sets the value to be compared with the value of . This is a dependency property. + /// + [SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods")] + public object Value + { + get + { + return (object)this.GetValue(DataTriggerBehavior.ValueProperty); + } + set + { + this.SetValue(DataTriggerBehavior.ValueProperty, value); + } + } - return false; + private static bool Compare(object leftOperand, ComparisonConditionType operatorType, object rightOperand) + { + if (leftOperand != null && rightOperand != null) + { + rightOperand = TypeConverterHelper.Convert(rightOperand.ToString(), leftOperand.GetType().FullName); } - /// - /// Evaluates both operands that implement the IComparable interface. - /// - private static bool EvaluateComparable(IComparable leftOperand, ComparisonConditionType operatorType, IComparable rightOperand) + IComparable leftComparableOperand = leftOperand as IComparable; + IComparable rightComparableOperand = rightOperand as IComparable; + if ((leftComparableOperand != null) && (rightComparableOperand != null)) { - object convertedOperand = null; - try - { - convertedOperand = Convert.ChangeType(rightOperand, leftOperand.GetType(), CultureInfo.CurrentCulture); - } - catch (FormatException) - { - // FormatException: Convert.ChangeType("hello", typeof(double), ...); - } - catch (InvalidCastException) - { - // InvalidCastException: Convert.ChangeType(4.0d, typeof(Rectangle), ...); - } + return DataTriggerBehavior.EvaluateComparable(leftComparableOperand, operatorType, rightComparableOperand); + } - if (convertedOperand == null) - { - return operatorType == ComparisonConditionType.NotEqual; - } + switch (operatorType) + { + case ComparisonConditionType.Equal: + return object.Equals(leftOperand, rightOperand); + + case ComparisonConditionType.NotEqual: + return !object.Equals(leftOperand, rightOperand); + + case ComparisonConditionType.LessThan: + case ComparisonConditionType.LessThanOrEqual: + case ComparisonConditionType.GreaterThan: + case ComparisonConditionType.GreaterThanOrEqual: + { + if (leftComparableOperand == null && rightComparableOperand == null) + { + throw new ArgumentException(string.Format( + CultureInfo.CurrentCulture, + ResourceHelper.InvalidOperands, + leftOperand != null ? leftOperand.GetType().Name : "null", + rightOperand != null ? rightOperand.GetType().Name : "null", + operatorType.ToString())); + } + else if (leftComparableOperand == null) + { + throw new ArgumentException(string.Format( + CultureInfo.CurrentCulture, + ResourceHelper.InvalidLeftOperand, + leftOperand != null ? leftOperand.GetType().Name : "null", + operatorType.ToString())); + } + else + { + throw new ArgumentException(string.Format( + CultureInfo.CurrentCulture, + ResourceHelper.InvalidRightOperand, + rightOperand != null ? rightOperand.GetType().Name : "null", + operatorType.ToString())); + } + } + } - int comparison = leftOperand.CompareTo((IComparable)convertedOperand); - switch (operatorType) - { - case ComparisonConditionType.Equal: - return comparison == 0; + return false; + } - case ComparisonConditionType.NotEqual: - return comparison != 0; + /// + /// Evaluates both operands that implement the IComparable interface. + /// + private static bool EvaluateComparable(IComparable leftOperand, ComparisonConditionType operatorType, IComparable rightOperand) + { + object convertedOperand = null; + try + { + convertedOperand = Convert.ChangeType(rightOperand, leftOperand.GetType(), CultureInfo.CurrentCulture); + } + catch (FormatException) + { + // FormatException: Convert.ChangeType("hello", typeof(double), ...); + } + catch (InvalidCastException) + { + // InvalidCastException: Convert.ChangeType(4.0d, typeof(Rectangle), ...); + } - case ComparisonConditionType.LessThan: - return comparison < 0; + if (convertedOperand == null) + { + return operatorType == ComparisonConditionType.NotEqual; + } - case ComparisonConditionType.LessThanOrEqual: - return comparison <= 0; + int comparison = leftOperand.CompareTo((IComparable)convertedOperand); + switch (operatorType) + { + case ComparisonConditionType.Equal: + return comparison == 0; + + case ComparisonConditionType.NotEqual: + return comparison != 0; - case ComparisonConditionType.GreaterThan: - return comparison > 0; + case ComparisonConditionType.LessThan: + return comparison < 0; - case ComparisonConditionType.GreaterThanOrEqual: - return comparison >= 0; - } + case ComparisonConditionType.LessThanOrEqual: + return comparison <= 0; - return false; + case ComparisonConditionType.GreaterThan: + return comparison > 0; + + case ComparisonConditionType.GreaterThanOrEqual: + return comparison >= 0; } - private static void OnValueChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args) + return false; + } + + private static void OnValueChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args) + { + DataTriggerBehavior dataTriggerBehavior = (DataTriggerBehavior)dependencyObject; + if (dataTriggerBehavior.AssociatedObject == null) { - DataTriggerBehavior dataTriggerBehavior = (DataTriggerBehavior)dependencyObject; - if (dataTriggerBehavior.AssociatedObject == null) - { - return; - } + return; + } - DataBindingHelper.RefreshDataBindingsOnActions(dataTriggerBehavior.Actions); + DataBindingHelper.RefreshDataBindingsOnActions(dataTriggerBehavior.Actions); - // Some value has changed--either the binding value, reference value, or the comparison condition. Re-evaluate the equation. - if (DataTriggerBehavior.Compare(dataTriggerBehavior.Binding, dataTriggerBehavior.ComparisonCondition, dataTriggerBehavior.Value)) - { - Interaction.ExecuteActions(dataTriggerBehavior.AssociatedObject, dataTriggerBehavior.Actions, args); - } + // Some value has changed--either the binding value, reference value, or the comparison condition. Re-evaluate the equation. + if (DataTriggerBehavior.Compare(dataTriggerBehavior.Binding, dataTriggerBehavior.ComparisonCondition, dataTriggerBehavior.Value)) + { + Interaction.ExecuteActions(dataTriggerBehavior.AssociatedObject, dataTriggerBehavior.Actions, args); } } } diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/EventTriggerBehavior.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/EventTriggerBehavior.cs index 76c97db..3850333 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/EventTriggerBehavior.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/EventTriggerBehavior.cs @@ -16,298 +16,297 @@ using System.Runtime.InteropServices.WindowsRuntime; #endif -namespace Microsoft.Xaml.Interactivity +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.")] +#endif +public sealed class EventTriggerBehavior : Trigger { /// - /// A behavior that listens for a specified event on its source and executes its actions when that event is fired. + /// Identifies the dependency property. /// -#if NET8_0_OR_GREATER - [RequiresUnreferencedCode("This behavior is not trim-safe.")] -#endif - public sealed class EventTriggerBehavior : Trigger - { - /// - /// 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; + [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 bool _isWindowsRuntimeEvent; - private Func _addEventHandlerMethod; - private Action _removeEventHandlerMethod; + private bool _isWindowsRuntimeEvent; + private Func _addEventHandlerMethod; + private Action _removeEventHandlerMethod; #endif - /// - /// Initializes a new instance of the class. - /// - public EventTriggerBehavior() + /// + /// Initializes a new instance of the class. + /// + public EventTriggerBehavior() + { + } + + /// + /// Gets or sets the name of the event to listen for. This is a dependency property. + /// + public string EventName + { + get { + return (string)this.GetValue(EventTriggerBehavior.EventNameProperty); } - /// - /// Gets or sets the name of the event to listen for. This is a dependency property. - /// - public string EventName + set { - get - { - return (string)this.GetValue(EventTriggerBehavior.EventNameProperty); - } - - set - { - this.SetValue(EventTriggerBehavior.EventNameProperty, value); - } + 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 + /// + /// 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 { - get - { - return (object)this.GetValue(EventTriggerBehavior.SourceObjectProperty); - } - - set - { - this.SetValue(EventTriggerBehavior.SourceObjectProperty, value); - } + return (object)this.GetValue(EventTriggerBehavior.SourceObjectProperty); } - /// - /// Called after the behavior is attached to the . - /// - protected override void OnAttached() + set { - base.OnAttached(); - this.SetResolvedSource(this.ComputeResolvedSource()); + 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() + /// + /// 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) { - base.OnDetaching(); - this.SetResolvedSource(null); + return; } - private void SetResolvedSource(object newSource) + if (this._resolvedSource != null) { - if (this.AssociatedObject == null || this._resolvedSource == newSource) - { - return; - } - - if (this._resolvedSource != null) - { - this.UnregisterEvent(this.EventName); - } + this.UnregisterEvent(this.EventName); + } - this._resolvedSource = newSource; + this._resolvedSource = newSource; - if (this._resolvedSource != null) - { - this.RegisterEvent(this.EventName); - } + if (this._resolvedSource != null) + { + this.RegisterEvent(this.EventName); } + } - private object ComputeResolvedSource() + 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) { - // 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.SourceObject; + } + + return this.AssociatedObject; + } - return this.AssociatedObject; + private void RegisterEvent(string eventName) + { + if (string.IsNullOrEmpty(eventName)) + { + return; } - private void RegisterEvent(string eventName) + if (eventName != "Loaded") { - if (string.IsNullOrEmpty(eventName)) + Type sourceObjectType = this._resolvedSource.GetType(); + EventInfo info = sourceObjectType.GetRuntimeEvent(eventName); + if (info == null) { return; } - if (eventName != "Loaded") - { - Type sourceObjectType = this._resolvedSource.GetType(); - EventInfo info = sourceObjectType.GetRuntimeEvent(eventName); - if (info == null) - { - return; - } - - MethodInfo methodInfo = typeof(EventTriggerBehavior).GetTypeInfo().GetDeclaredMethod("OnEvent"); - this._eventHandler = methodInfo.CreateDelegate(info.EventHandlerType, this); + MethodInfo methodInfo = typeof(EventTriggerBehavior).GetTypeInfo().GetDeclaredMethod("OnEvent"); + this._eventHandler = methodInfo.CreateDelegate(info.EventHandlerType, this); #if NET8_0_OR_GREATER - info.AddEventHandler(this._resolvedSource, this._eventHandler); + info.AddEventHandler(this._resolvedSource, this._eventHandler); #else - this._isWindowsRuntimeEvent = EventTriggerBehavior.IsWindowsRuntimeEvent(info); - if (this._isWindowsRuntimeEvent) - { - this._addEventHandlerMethod = add => (EventRegistrationToken)info.AddMethod.Invoke(this._resolvedSource, new object[] { add }); - this._removeEventHandlerMethod = token => info.RemoveMethod.Invoke(this._resolvedSource, new object[] { token }); - - WindowsRuntimeMarshal.AddEventHandler(this._addEventHandlerMethod, this._removeEventHandlerMethod, this._eventHandler); - } - else - { - info.AddEventHandler(this._resolvedSource, this._eventHandler); - } -#endif + this._isWindowsRuntimeEvent = EventTriggerBehavior.IsWindowsRuntimeEvent(info); + if (this._isWindowsRuntimeEvent) + { + this._addEventHandlerMethod = add => (EventRegistrationToken)info.AddMethod.Invoke(this._resolvedSource, new object[] { add }); + this._removeEventHandlerMethod = token => info.RemoveMethod.Invoke(this._resolvedSource, new object[] { token }); + + WindowsRuntimeMarshal.AddEventHandler(this._addEventHandlerMethod, this._removeEventHandlerMethod, this._eventHandler); } - else if (!this._isLoadedEventRegistered) + else { - FrameworkElement element = this._resolvedSource as FrameworkElement; - if (element != null && !EventTriggerBehaviorHelpers.IsElementLoaded(element)) - { - this._isLoadedEventRegistered = true; - element.Loaded += this.OnEvent; - } + info.AddEventHandler(this._resolvedSource, this._eventHandler); } +#endif } - - private void UnregisterEvent(string eventName) + else if (!this._isLoadedEventRegistered) { - if (string.IsNullOrEmpty(eventName)) + FrameworkElement element = this._resolvedSource as FrameworkElement; + if (element != null && !EventTriggerBehaviorHelpers.IsElementLoaded(element)) { - return; + this._isLoadedEventRegistered = true; + element.Loaded += this.OnEvent; } + } + } - if (eventName != "Loaded") + private void UnregisterEvent(string eventName) + { + if (string.IsNullOrEmpty(eventName)) + { + return; + } + + if (eventName != "Loaded") + { + if (this._eventHandler == null) { - if (this._eventHandler == null) - { - return; - } + return; + } - EventInfo info = this._resolvedSource.GetType().GetRuntimeEvent(eventName); + EventInfo info = this._resolvedSource.GetType().GetRuntimeEvent(eventName); #if NET8_0_OR_GREATER - info.RemoveEventHandler(this._resolvedSource, this._eventHandler); + 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 (this._isWindowsRuntimeEvent) + { + WindowsRuntimeMarshal.RemoveEventHandler(this._removeEventHandlerMethod, this._eventHandler); } - else if (this._isLoadedEventRegistered) + else { - this._isLoadedEventRegistered = false; - FrameworkElement element = (FrameworkElement)this._resolvedSource; - element.Loaded -= this.OnEvent; + info.RemoveEventHandler(this._resolvedSource, this._eventHandler); } - } +#endif - private void OnEvent(object sender, object eventArgs) - { - Interaction.ExecuteActions(this._resolvedSource, this.Actions, eventArgs); + this._eventHandler = null; } - - private static void OnSourceObjectChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args) + else if (this._isLoadedEventRegistered) { - EventTriggerBehavior behavior = (EventTriggerBehavior)dependencyObject; - behavior.SetResolvedSource(behavior.ComputeResolvedSource()); + this._isLoadedEventRegistered = false; + FrameworkElement element = (FrameworkElement)this._resolvedSource; + element.Loaded -= this.OnEvent; } + } - private static void OnEventNameChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args) - { - EventTriggerBehavior behavior = (EventTriggerBehavior)dependencyObject; - if (behavior.AssociatedObject == null || behavior._resolvedSource == null) - { - return; - } + private void OnEvent(object sender, object eventArgs) + { + Interaction.ExecuteActions(this._resolvedSource, this.Actions, eventArgs); + } - string oldEventName = (string)args.OldValue; - string newEventName = (string)args.NewValue; + private static void OnSourceObjectChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args) + { + EventTriggerBehavior behavior = (EventTriggerBehavior)dependencyObject; + behavior.SetResolvedSource(behavior.ComputeResolvedSource()); + } - behavior.UnregisterEvent(oldEventName); - behavior.RegisterEvent(newEventName); + 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); + } + #if !NET8_0_OR_GREATER - private static bool IsWindowsRuntimeEvent(EventInfo eventInfo) - { - return eventInfo != null && - EventTriggerBehavior.IsWindowsRuntimeType(eventInfo.EventHandlerType) && - EventTriggerBehavior.IsWindowsRuntimeType(eventInfo.DeclaringType); - } + private static bool IsWindowsRuntimeEvent(EventInfo eventInfo) + { + return eventInfo != null && + EventTriggerBehavior.IsWindowsRuntimeType(eventInfo.EventHandlerType) && + EventTriggerBehavior.IsWindowsRuntimeType(eventInfo.DeclaringType); + } - private static bool IsWindowsRuntimeType(Type type) + private static bool IsWindowsRuntimeType(Type type) + { + if (type != null) { - 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. - return type.AssemblyQualifiedName.EndsWith("ContentType=WindowsRuntime", StringComparison.Ordinal); - } - - return false; + // 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. + return type.AssemblyQualifiedName.EndsWith("ContentType=WindowsRuntime", StringComparison.Ordinal); } -#endif + + return false; } +#endif +} - internal static class EventTriggerBehaviorHelpers +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) { - // 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) { - 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; - } + return false; + } - 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); - } + UIElement rootVisual = default; + if (element.XamlRoot != null) + { + rootVisual = element.XamlRoot.Content; + } + else if (Window.Current != null) + { + rootVisual = Window.Current.Content; + } - return (parent != null || (rootVisual != null && element == rootVisual)); + 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/GoToStateAction.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/GoToStateAction.cs index 5b8b112..f8b1e82 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/GoToStateAction.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/GoToStateAction.cs @@ -13,133 +13,132 @@ using Windows.UI.Xaml.Controls; #endif -namespace Microsoft.Xaml.Interactivity +namespace Microsoft.Xaml.Interactivity; + +/// +/// An action that will transition a to a specified when executed. +/// +/// +/// If the property is set, this action will attempt to change the state of the targeted element. If it is not set, the action walks +/// the element tree in an attempt to locate an alternative target that defines states. and are +/// two common results. +/// +public sealed class GoToStateAction : DependencyObject, IAction { /// - /// An action that will transition a to a specified when executed. + /// Identifies the dependency property. /// - /// - /// If the property is set, this action will attempt to change the state of the targeted element. If it is not set, the action walks - /// the element tree in an attempt to locate an alternative target that defines states. and are - /// two common results. - /// - public sealed class GoToStateAction : DependencyObject, IAction - { - /// - /// Identifies the dependency property. - /// - [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] - public static readonly DependencyProperty UseTransitionsProperty = DependencyProperty.Register( - "UseTransitions", - typeof(bool), - typeof(GoToStateAction), - new PropertyMetadata(true)); + [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] + public static readonly DependencyProperty UseTransitionsProperty = DependencyProperty.Register( + "UseTransitions", + typeof(bool), + typeof(GoToStateAction), + new PropertyMetadata(true)); - /// - /// Identifies the dependency property. - /// - [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] - public static readonly DependencyProperty StateNameProperty = DependencyProperty.Register( - "StateName", - typeof(string), - typeof(GoToStateAction), - new PropertyMetadata(null)); + /// + /// Identifies the dependency property. + /// + [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] + public static readonly DependencyProperty StateNameProperty = DependencyProperty.Register( + "StateName", + typeof(string), + typeof(GoToStateAction), + new PropertyMetadata(null)); - /// - /// Identifies the dependency property. - /// - [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] - public static readonly DependencyProperty TargetObjectProperty = DependencyProperty.Register( - "TargetObject", - typeof(FrameworkElement), - typeof(GoToStateAction), - new PropertyMetadata(null)); + /// + /// Identifies the dependency property. + /// + [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] + public static readonly DependencyProperty TargetObjectProperty = DependencyProperty.Register( + "TargetObject", + typeof(FrameworkElement), + typeof(GoToStateAction), + new PropertyMetadata(null)); - /// - /// Gets or sets whether or not to use a to transition between states. This is a dependency property. - /// - public bool UseTransitions + /// + /// Gets or sets whether or not to use a to transition between states. This is a dependency property. + /// + public bool UseTransitions + { + get { - get - { - return (bool)this.GetValue(GoToStateAction.UseTransitionsProperty); - } - set - { - this.SetValue(GoToStateAction.UseTransitionsProperty, value); - } + return (bool)this.GetValue(GoToStateAction.UseTransitionsProperty); } - - /// - /// Gets or sets the name of the . This is a dependency property. - /// - public string StateName + set { - get - { - return (string)this.GetValue(GoToStateAction.StateNameProperty); - } - set - { - this.SetValue(GoToStateAction.StateNameProperty, value); - } + this.SetValue(GoToStateAction.UseTransitionsProperty, value); } + } - /// - /// Gets or sets the target object. This is a dependency property. - /// - public FrameworkElement TargetObject + /// + /// Gets or sets the name of the . This is a dependency property. + /// + public string StateName + { + get { - get - { - return (FrameworkElement)this.GetValue(GoToStateAction.TargetObjectProperty); - } - set - { - this.SetValue(GoToStateAction.TargetObjectProperty, value); - } + return (string)this.GetValue(GoToStateAction.StateNameProperty); } - - /// - /// Executes the action. - /// - /// The that is passed to the action by the behavior. Generally this is or a target object. - /// The value of this parameter is determined by the caller. - /// True if the transition to the specified state succeeds; else false. - public object Execute(object sender, object parameter) + set { - if (string.IsNullOrEmpty(this.StateName)) - { - return false; - } + this.SetValue(GoToStateAction.StateNameProperty, value); + } + } - if (this.ReadLocalValue(GoToStateAction.TargetObjectProperty) != DependencyProperty.UnsetValue) - { - Control control = this.TargetObject as Control; - if (control == null) - { - return false; - } + /// + /// Gets or sets the target object. This is a dependency property. + /// + public FrameworkElement TargetObject + { + get + { + return (FrameworkElement)this.GetValue(GoToStateAction.TargetObjectProperty); + } + set + { + this.SetValue(GoToStateAction.TargetObjectProperty, value); + } + } - return VisualStateUtilities.GoToState(control, this.StateName, this.UseTransitions); - } + /// + /// Executes the action. + /// + /// The that is passed to the action by the behavior. Generally this is or a target object. + /// The value of this parameter is determined by the caller. + /// True if the transition to the specified state succeeds; else false. + public object Execute(object sender, object parameter) + { + if (string.IsNullOrEmpty(this.StateName)) + { + return false; + } - FrameworkElement element = sender as FrameworkElement; - if (element == null || !EventTriggerBehaviorHelpers.IsElementLoaded(element)) + if (this.ReadLocalValue(GoToStateAction.TargetObjectProperty) != DependencyProperty.UnsetValue) + { + Control control = this.TargetObject as Control; + if (control == null) { return false; } - Control resolvedControl = VisualStateUtilities.FindNearestStatefulControl(element); - if (resolvedControl == null) - { - throw new InvalidOperationException(string.Format( - CultureInfo.CurrentCulture, - ResourceHelper.GoToStateActionTargetHasNoStateGroups, - element.Name)); - } + return VisualStateUtilities.GoToState(control, this.StateName, this.UseTransitions); + } - return VisualStateUtilities.GoToState(resolvedControl, this.StateName, this.UseTransitions); + FrameworkElement element = sender as FrameworkElement; + if (element == null || !EventTriggerBehaviorHelpers.IsElementLoaded(element)) + { + return false; } + + Control resolvedControl = VisualStateUtilities.FindNearestStatefulControl(element); + if (resolvedControl == null) + { + throw new InvalidOperationException(string.Format( + CultureInfo.CurrentCulture, + ResourceHelper.GoToStateActionTargetHasNoStateGroups, + element.Name)); + } + + return VisualStateUtilities.GoToState(resolvedControl, this.StateName, this.UseTransitions); } } diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/IncrementalUpdateBehavior.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/IncrementalUpdateBehavior.cs index edf6027..2b47438 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/IncrementalUpdateBehavior.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/IncrementalUpdateBehavior.cs @@ -17,433 +17,432 @@ using Windows.UI.Xaml.Media; #endif -namespace Microsoft.Xaml.Interactivity +namespace Microsoft.Xaml.Interactivity; + +/// +/// A behavior that allows incremental updating of and contents to support faster updating. +/// By attaching this behavior to elements in the used by these views, some of the updates can be deferred until there is render time available, resulting in a smoother experience. +/// +public sealed class IncrementalUpdateBehavior : Behavior { /// - /// A behavior that allows incremental updating of and contents to support faster updating. - /// By attaching this behavior to elements in the used by these views, some of the updates can be deferred until there is render time available, resulting in a smoother experience. + /// Identifies the dependency property. + /// + [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] + public static readonly DependencyProperty PhaseProperty = DependencyProperty.Register( + "Phase", + typeof(int), + typeof(IncrementalUpdateBehavior), + new PropertyMetadata((int)1, new PropertyChangedCallback(IncrementalUpdateBehavior.OnPhaseChanged))); + + /// + /// Identifies the dependency property. /// - public sealed class IncrementalUpdateBehavior : Behavior + private static readonly DependencyProperty IncrementalUpdaterProperty = DependencyProperty.RegisterAttached( + "IncrementalUpdater", + typeof(IncrementalUpdater), + typeof(IncrementalUpdateBehavior), + new PropertyMetadata(null, new PropertyChangedCallback(IncrementalUpdateBehavior.OnIncrementalUpdaterChanged))); + + private IncrementalUpdater _updater = null; + + /// + /// Gets or sets the relative priority of this incremental update. Lower Phase values are addressed first. + /// + public int Phase + { + get { return (int)this.GetValue(IncrementalUpdateBehavior.PhaseProperty); } + set { this.SetValue(IncrementalUpdateBehavior.PhaseProperty, value); } + } + + private static void OnPhaseChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args) { - /// - /// Identifies the dependency property. - /// - [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] - public static readonly DependencyProperty PhaseProperty = DependencyProperty.Register( - "Phase", - typeof(int), - typeof(IncrementalUpdateBehavior), - new PropertyMetadata((int)1, new PropertyChangedCallback(IncrementalUpdateBehavior.OnPhaseChanged))); - - /// - /// Identifies the dependency property. - /// - private static readonly DependencyProperty IncrementalUpdaterProperty = DependencyProperty.RegisterAttached( - "IncrementalUpdater", - typeof(IncrementalUpdater), - typeof(IncrementalUpdateBehavior), - new PropertyMetadata(null, new PropertyChangedCallback(IncrementalUpdateBehavior.OnIncrementalUpdaterChanged))); - - private IncrementalUpdater _updater = null; - - /// - /// Gets or sets the relative priority of this incremental update. Lower Phase values are addressed first. - /// - public int Phase + IncrementalUpdateBehavior behavior = (IncrementalUpdateBehavior)sender; + IncrementalUpdater incrementalUpdater = behavior.FindUpdater(); + FrameworkElement frameworkElement = behavior.AssociatedObject; + + if (incrementalUpdater != null && frameworkElement != null) { - get { return (int)this.GetValue(IncrementalUpdateBehavior.PhaseProperty); } - set { this.SetValue(IncrementalUpdateBehavior.PhaseProperty, value); } + incrementalUpdater.UncachePhaseElement(frameworkElement, (int)args.OldValue); + incrementalUpdater.CachePhaseElement(frameworkElement, (int)args.NewValue); } + } - private static void OnPhaseChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args) - { - IncrementalUpdateBehavior behavior = (IncrementalUpdateBehavior)sender; - IncrementalUpdater incrementalUpdater = behavior.FindUpdater(); - FrameworkElement frameworkElement = behavior.AssociatedObject; + private static IncrementalUpdater GetIncrementalUpdater(DependencyObject dependencyObject) + { + return (IncrementalUpdater)dependencyObject.GetValue(IncrementalUpdateBehavior.IncrementalUpdaterProperty); + } - if (incrementalUpdater != null && frameworkElement != null) - { - incrementalUpdater.UncachePhaseElement(frameworkElement, (int)args.OldValue); - incrementalUpdater.CachePhaseElement(frameworkElement, (int)args.NewValue); - } - } + private static void SetIncrementalUpdater(DependencyObject dependencyObject, IncrementalUpdater value) + { + dependencyObject.SetValue(IncrementalUpdateBehavior.IncrementalUpdaterProperty, value); + } - private static IncrementalUpdater GetIncrementalUpdater(DependencyObject dependencyObject) + private static void OnIncrementalUpdaterChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args) + { + if (args.OldValue != null) { - return (IncrementalUpdater)dependencyObject.GetValue(IncrementalUpdateBehavior.IncrementalUpdaterProperty); + IncrementalUpdater incrementalUpdater = (IncrementalUpdater)args.OldValue; + incrementalUpdater.Detach(); } - - private static void SetIncrementalUpdater(DependencyObject dependencyObject, IncrementalUpdater value) + if (args.NewValue != null) { - dependencyObject.SetValue(IncrementalUpdateBehavior.IncrementalUpdaterProperty, value); + IncrementalUpdater incrementalUpdater = (IncrementalUpdater)args.NewValue; + incrementalUpdater.Attach(sender); } + } + + private void OnAssociatedObjectLoaded(object sender, RoutedEventArgs e) + { + IncrementalUpdater incrementalUpdater = this.FindUpdater(); - private static void OnIncrementalUpdaterChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args) + if (incrementalUpdater != null) { - if (args.OldValue != null) - { - IncrementalUpdater incrementalUpdater = (IncrementalUpdater)args.OldValue; - incrementalUpdater.Detach(); - } - if (args.NewValue != null) - { - IncrementalUpdater incrementalUpdater = (IncrementalUpdater)args.NewValue; - incrementalUpdater.Attach(sender); - } + incrementalUpdater.CachePhaseElement(this.AssociatedObject, this.Phase); } + } - private void OnAssociatedObjectLoaded(object sender, RoutedEventArgs e) + private void OnAssociatedObjectUnloaded(object sender, RoutedEventArgs e) + { + if (this._updater != null) { - IncrementalUpdater incrementalUpdater = this.FindUpdater(); - - if (incrementalUpdater != null) - { - incrementalUpdater.CachePhaseElement(this.AssociatedObject, this.Phase); - } + this._updater.UncachePhaseElement(this.AssociatedObject, this.Phase); } - private void OnAssociatedObjectUnloaded(object sender, RoutedEventArgs e) - { - if (this._updater != null) - { - this._updater.UncachePhaseElement(this.AssociatedObject, this.Phase); - } + this._updater = null; + } - this._updater = null; + private IncrementalUpdater FindUpdater() + { + if (this._updater != null) + { + return this._updater; } - private IncrementalUpdater FindUpdater() + DependencyObject ancestor = this.AssociatedObject; + while (ancestor != null) { - if (this._updater != null) - { - return this._updater; - } + DependencyObject parent = VisualTreeHelper.GetParent(ancestor); + ListViewBase listView = parent as ListViewBase; - DependencyObject ancestor = this.AssociatedObject; - while (ancestor != null) + if (listView != null) { - DependencyObject parent = VisualTreeHelper.GetParent(ancestor); - ListViewBase listView = parent as ListViewBase; - - if (listView != null) + IncrementalUpdater currentUpdater = IncrementalUpdateBehavior.GetIncrementalUpdater(listView); + if (currentUpdater == null) { - IncrementalUpdater currentUpdater = IncrementalUpdateBehavior.GetIncrementalUpdater(listView); - if (currentUpdater == null) - { - currentUpdater = new IncrementalUpdater(); + currentUpdater = new IncrementalUpdater(); - IncrementalUpdateBehavior.SetIncrementalUpdater(listView, currentUpdater); - } - return currentUpdater; + IncrementalUpdateBehavior.SetIncrementalUpdater(listView, currentUpdater); } - ancestor = parent; + return currentUpdater; } - - return null; + ancestor = parent; } - /// - /// Called after the behavior is attached to the . - /// - protected override void OnAttached() - { - base.OnAttached(); + return null; + } - this.AssociatedObject.Loaded += this.OnAssociatedObjectLoaded; - this.AssociatedObject.Unloaded += this.OnAssociatedObjectUnloaded; - } + /// + /// Called after the behavior is attached to the . + /// + protected override void OnAttached() + { + base.OnAttached(); - /// - /// Called when the behavior is being detached from its . - /// - protected override void OnDetaching() - { - base.OnDetaching(); + this.AssociatedObject.Loaded += this.OnAssociatedObjectLoaded; + this.AssociatedObject.Unloaded += this.OnAssociatedObjectUnloaded; + } - this.AssociatedObject.Loaded -= this.OnAssociatedObjectLoaded; - this.AssociatedObject.Unloaded -= this.OnAssociatedObjectUnloaded; - // no need to perform the work that Unloaded would have done - that's just housekeeping on the cache, which is now going away - } + /// + /// Called when the behavior is being detached from its . + /// + protected override void OnDetaching() + { + base.OnDetaching(); + + this.AssociatedObject.Loaded -= this.OnAssociatedObjectLoaded; + this.AssociatedObject.Unloaded -= this.OnAssociatedObjectUnloaded; + // no need to perform the work that Unloaded would have done - that's just housekeeping on the cache, which is now going away + } - private class IncrementalUpdater + private class IncrementalUpdater + { + private ListViewBase _associatedListViewBase = null; + private Dictionary _elementCache = new Dictionary(); + + private class PhasedElementRecord { - private ListViewBase _associatedListViewBase = null; - private Dictionary _elementCache = new Dictionary(); + private readonly FrameworkElement _frameworkElement; + private object _localOpacity; + private object _localDataContext; + private bool _isFrozen; - private class PhasedElementRecord + public PhasedElementRecord(FrameworkElement frameworkElement) { - private readonly FrameworkElement _frameworkElement; - private object _localOpacity; - private object _localDataContext; - private bool _isFrozen; + this._frameworkElement = frameworkElement; + } + + public FrameworkElement FrameworkElement { get { return this._frameworkElement; } } - public PhasedElementRecord(FrameworkElement frameworkElement) + public void FreezeAndHide() + { + if (this._isFrozen) { - this._frameworkElement = frameworkElement; + return; } - public FrameworkElement FrameworkElement { get { return this._frameworkElement; } } + this._isFrozen = true; + this._localOpacity = this._frameworkElement.ReadLocalValue(FrameworkElement.OpacityProperty); + this._localDataContext = this._frameworkElement.ReadLocalValue(FrameworkElement.DataContextProperty); + this._frameworkElement.Opacity = 0.0; + this._frameworkElement.DataContext = this._frameworkElement.DataContext; + } - public void FreezeAndHide() + public void ThawAndShow() + { + if (!this._isFrozen) { - if (this._isFrozen) - { - return; - } - - this._isFrozen = true; - this._localOpacity = this._frameworkElement.ReadLocalValue(FrameworkElement.OpacityProperty); - this._localDataContext = this._frameworkElement.ReadLocalValue(FrameworkElement.DataContextProperty); - this._frameworkElement.Opacity = 0.0; - this._frameworkElement.DataContext = this._frameworkElement.DataContext; + return; } - public void ThawAndShow() + if (this._localOpacity != DependencyProperty.UnsetValue) { - if (!this._isFrozen) - { - return; - } - - if (this._localOpacity != DependencyProperty.UnsetValue) - { - this._frameworkElement.SetValue(FrameworkElement.OpacityProperty, this._localOpacity); - } - else - { - this._frameworkElement.ClearValue(FrameworkElement.OpacityProperty); - } - - if (this._localDataContext != DependencyProperty.UnsetValue) - { - this._frameworkElement.SetValue(FrameworkElement.DataContextProperty, this._localDataContext); - } - else - { - this._frameworkElement.ClearValue(FrameworkElement.DataContextProperty); - } - - this._isFrozen = false; + this._frameworkElement.SetValue(FrameworkElement.OpacityProperty, this._localOpacity); } - } - - private class ElementCacheRecord - { - private List _phases = new List(); - private List> _elementsByPhase = new List>(); - - public List Phases + else { - get { return this._phases; } + this._frameworkElement.ClearValue(FrameworkElement.OpacityProperty); } - public List> ElementsByPhase + if (this._localDataContext != DependencyProperty.UnsetValue) + { + this._frameworkElement.SetValue(FrameworkElement.DataContextProperty, this._localDataContext); + } + else { - get { return this._elementsByPhase; } + this._frameworkElement.ClearValue(FrameworkElement.DataContextProperty); } + + this._isFrozen = false; } + } + + private class ElementCacheRecord + { + private List _phases = new List(); + private List> _elementsByPhase = new List>(); - private void OnContainerContentChanging(ListViewBase sender, ContainerContentChangingEventArgs e) + public List Phases { - UIElement contentTemplateRoot = e.ItemContainer.ContentTemplateRoot; + get { return this._phases; } + } - ElementCacheRecord elementCacheRecord; - if (this._elementCache.TryGetValue(contentTemplateRoot, out elementCacheRecord)) - { - if (!e.InRecycleQueue) - { - foreach (List phaseRecord in elementCacheRecord.ElementsByPhase) - { - foreach (PhasedElementRecord phasedElementRecord in phaseRecord) - { - phasedElementRecord.FreezeAndHide(); - } - } + public List> ElementsByPhase + { + get { return this._elementsByPhase; } + } + } - if (elementCacheRecord.Phases.Count > 0) - { - e.RegisterUpdateCallback((uint)elementCacheRecord.Phases[0], this.OnContainerContentChangingCallback); - } + private void OnContainerContentChanging(ListViewBase sender, ContainerContentChangingEventArgs e) + { + UIElement contentTemplateRoot = e.ItemContainer.ContentTemplateRoot; - // set the DataContext manually since we inhibit default operation by setting e.Handled=true - ((FrameworkElement)contentTemplateRoot).DataContext = e.Item; - } - else + ElementCacheRecord elementCacheRecord; + if (this._elementCache.TryGetValue(contentTemplateRoot, out elementCacheRecord)) + { + if (!e.InRecycleQueue) + { + foreach (List phaseRecord in elementCacheRecord.ElementsByPhase) { - // clear the DataContext manually since we inhibit default operation by setting e.Handled=true - contentTemplateRoot.ClearValue(FrameworkElement.DataContextProperty); - - foreach (List phaseRecord in elementCacheRecord.ElementsByPhase) + foreach (PhasedElementRecord phasedElementRecord in phaseRecord) { - foreach (PhasedElementRecord phasedElementRecord in phaseRecord) - { - phasedElementRecord.ThawAndShow(); - } + phasedElementRecord.FreezeAndHide(); } } - } - } - private void OnContainerContentChangingCallback(ListViewBase sender, ContainerContentChangingEventArgs e) - { - UIElement contentTemplateRoot = e.ItemContainer.ContentTemplateRoot; + if (elementCacheRecord.Phases.Count > 0) + { + e.RegisterUpdateCallback((uint)elementCacheRecord.Phases[0], this.OnContainerContentChangingCallback); + } - ElementCacheRecord elementCacheRecord; - if (this._elementCache.TryGetValue(contentTemplateRoot, out elementCacheRecord)) + // set the DataContext manually since we inhibit default operation by setting e.Handled=true + ((FrameworkElement)contentTemplateRoot).DataContext = e.Item; + } + else { - int phaseIndex = elementCacheRecord.Phases.BinarySearch((int)e.Phase); + // clear the DataContext manually since we inhibit default operation by setting e.Handled=true + contentTemplateRoot.ClearValue(FrameworkElement.DataContextProperty); - if (phaseIndex >= 0) + foreach (List phaseRecord in elementCacheRecord.ElementsByPhase) { - foreach (PhasedElementRecord phasedElementRecord in elementCacheRecord.ElementsByPhase[phaseIndex]) + foreach (PhasedElementRecord phasedElementRecord in phaseRecord) { phasedElementRecord.ThawAndShow(); } - - phaseIndex++; - } - else - { - // don't know why this phase was not found, but by BinarySearch rules, ~phaseIndex is the place - // where it would be inserted, thus the item there has the next higher number. - phaseIndex = ~phaseIndex; - } - - if (phaseIndex < elementCacheRecord.Phases.Count) - { - e.RegisterUpdateCallback((uint)elementCacheRecord.Phases[phaseIndex], this.OnContainerContentChangingCallback); } } } + } + + private void OnContainerContentChangingCallback(ListViewBase sender, ContainerContentChangingEventArgs e) + { + UIElement contentTemplateRoot = e.ItemContainer.ContentTemplateRoot; - private static UIElement FindContentTemplateRoot(FrameworkElement phaseElement) + ElementCacheRecord elementCacheRecord; + if (this._elementCache.TryGetValue(contentTemplateRoot, out elementCacheRecord)) { - DependencyObject ancestor = phaseElement; - while (ancestor != null) - { - DependencyObject parent = VisualTreeHelper.GetParent(ancestor); - SelectorItem item = parent as SelectorItem; + int phaseIndex = elementCacheRecord.Phases.BinarySearch((int)e.Phase); - if (item != null) + if (phaseIndex >= 0) + { + foreach (PhasedElementRecord phasedElementRecord in elementCacheRecord.ElementsByPhase[phaseIndex]) { - return item.ContentTemplateRoot; + phasedElementRecord.ThawAndShow(); } - ancestor = parent; + + phaseIndex++; + } + else + { + // don't know why this phase was not found, but by BinarySearch rules, ~phaseIndex is the place + // where it would be inserted, thus the item there has the next higher number. + phaseIndex = ~phaseIndex; } - return null; + if (phaseIndex < elementCacheRecord.Phases.Count) + { + e.RegisterUpdateCallback((uint)elementCacheRecord.Phases[phaseIndex], this.OnContainerContentChangingCallback); + } } + } - public void CachePhaseElement(FrameworkElement phaseElement, int phase) + private static UIElement FindContentTemplateRoot(FrameworkElement phaseElement) + { + DependencyObject ancestor = phaseElement; + while (ancestor != null) { - if (phase < 0) + DependencyObject parent = VisualTreeHelper.GetParent(ancestor); + SelectorItem item = parent as SelectorItem; + + if (item != null) { - throw new ArgumentOutOfRangeException(nameof(phase)); + return item.ContentTemplateRoot; } + ancestor = parent; + } + + return null; + } - if (phase <= 0) + public void CachePhaseElement(FrameworkElement phaseElement, int phase) + { + if (phase < 0) + { + throw new ArgumentOutOfRangeException(nameof(phase)); + } + + if (phase <= 0) + { + return; + } + + UIElement contentTemplateRoot = IncrementalUpdater.FindContentTemplateRoot(phaseElement); + if (contentTemplateRoot != null) + { + // get the cache for this element + ElementCacheRecord elementCacheRecord; + if (!this._elementCache.TryGetValue(contentTemplateRoot, out elementCacheRecord)) { - return; + elementCacheRecord = new ElementCacheRecord(); + this._elementCache.Add(contentTemplateRoot, elementCacheRecord); } - UIElement contentTemplateRoot = IncrementalUpdater.FindContentTemplateRoot(phaseElement); - if (contentTemplateRoot != null) + // get the cache for this phase + int phaseIndex = elementCacheRecord.Phases.BinarySearch(phase); + + if (phaseIndex < 0) { - // get the cache for this element - ElementCacheRecord elementCacheRecord; - if (!this._elementCache.TryGetValue(contentTemplateRoot, out elementCacheRecord)) - { - elementCacheRecord = new ElementCacheRecord(); - this._elementCache.Add(contentTemplateRoot, elementCacheRecord); - } + // not found - insert + phaseIndex = ~phaseIndex; + elementCacheRecord.Phases.Insert(phaseIndex, phase); + elementCacheRecord.ElementsByPhase.Insert(phaseIndex, new List()); + } - // get the cache for this phase - int phaseIndex = elementCacheRecord.Phases.BinarySearch(phase); + List phasedElementRecords = elementCacheRecord.ElementsByPhase[phaseIndex]; - if (phaseIndex < 0) + // first see if the element is already there + for (int i = 0; i < phasedElementRecords.Count; i++) + { + if (phasedElementRecords[i].FrameworkElement == phaseElement) { - // not found - insert - phaseIndex = ~phaseIndex; - elementCacheRecord.Phases.Insert(phaseIndex, phase); - elementCacheRecord.ElementsByPhase.Insert(phaseIndex, new List()); + return; } + } - List phasedElementRecords = elementCacheRecord.ElementsByPhase[phaseIndex]; - - // first see if the element is already there - for (int i = 0; i < phasedElementRecords.Count; i++) - { - if (phasedElementRecords[i].FrameworkElement == phaseElement) - { - return; - } - } + // insert the element + phasedElementRecords.Add(new PhasedElementRecord(phaseElement)); + } + } - // insert the element - phasedElementRecords.Add(new PhasedElementRecord(phaseElement)); - } + public void UncachePhaseElement(FrameworkElement phaseElement, int phase) + { + if (phase <= 0) + { + return; } - public void UncachePhaseElement(FrameworkElement phaseElement, int phase) + UIElement contentTemplateRoot = IncrementalUpdater.FindContentTemplateRoot(phaseElement); + if (contentTemplateRoot != null) { - if (phase <= 0) + // get the cache for this element + ElementCacheRecord elementCacheRecord; + if (this._elementCache.TryGetValue(contentTemplateRoot, out elementCacheRecord)) { - return; - } + // get the cache for this phase + int phaseIndex = elementCacheRecord.Phases.BinarySearch(phase); - UIElement contentTemplateRoot = IncrementalUpdater.FindContentTemplateRoot(phaseElement); - if (contentTemplateRoot != null) - { - // get the cache for this element - ElementCacheRecord elementCacheRecord; - if (this._elementCache.TryGetValue(contentTemplateRoot, out elementCacheRecord)) + if (phaseIndex >= 0) { - // get the cache for this phase - int phaseIndex = elementCacheRecord.Phases.BinarySearch(phase); + // remove the element: the linear search here is not spectacular but the list should be very short + List phasedElementRecords = elementCacheRecord.ElementsByPhase[phaseIndex]; - if (phaseIndex >= 0) + for (int i = 0; i < phasedElementRecords.Count; i++) { - // remove the element: the linear search here is not spectacular but the list should be very short - List phasedElementRecords = elementCacheRecord.ElementsByPhase[phaseIndex]; - - for (int i = 0; i < phasedElementRecords.Count; i++) + if (phasedElementRecords[i].FrameworkElement == phaseElement) { - if (phasedElementRecords[i].FrameworkElement == phaseElement) - { - phasedElementRecords[i].ThawAndShow(); + phasedElementRecords[i].ThawAndShow(); - phasedElementRecords.RemoveAt(i); + phasedElementRecords.RemoveAt(i); - if (phasedElementRecords.Count == 0) - { - elementCacheRecord.Phases.RemoveAt(phaseIndex); - elementCacheRecord.ElementsByPhase.RemoveAt(phaseIndex); - } + if (phasedElementRecords.Count == 0) + { + elementCacheRecord.Phases.RemoveAt(phaseIndex); + elementCacheRecord.ElementsByPhase.RemoveAt(phaseIndex); } } } } } } + } - public void Attach(DependencyObject dependencyObject) - { - this._associatedListViewBase = dependencyObject as ListViewBase; + public void Attach(DependencyObject dependencyObject) + { + this._associatedListViewBase = dependencyObject as ListViewBase; - if (this._associatedListViewBase != null) - { - this._associatedListViewBase.ContainerContentChanging += this.OnContainerContentChanging; - } + if (this._associatedListViewBase != null) + { + this._associatedListViewBase.ContainerContentChanging += this.OnContainerContentChanging; } + } - public void Detach() + public void Detach() + { + if (this._associatedListViewBase != null) { - if (this._associatedListViewBase != null) - { - this._associatedListViewBase.ContainerContentChanging -= this.OnContainerContentChanging; - } - this._associatedListViewBase = null; + this._associatedListViewBase.ContainerContentChanging -= this.OnContainerContentChanging; } + this._associatedListViewBase = null; } } } diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/InvokeCommandAction.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/InvokeCommandAction.cs index 3eef9bd..3f5e7b7 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/InvokeCommandAction.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/InvokeCommandAction.cs @@ -13,183 +13,182 @@ using Windows.UI.Xaml.Data; #endif -namespace Microsoft.Xaml.Interactivity +namespace Microsoft.Xaml.Interactivity; + +/// +/// Executes a specified when invoked. +/// +public sealed class InvokeCommandAction : DependencyObject, IAction { /// - /// Executes a specified when invoked. + /// Identifies the dependency property. + /// + [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] + public static readonly DependencyProperty CommandProperty = DependencyProperty.Register( + "Command", + typeof(ICommand), + typeof(InvokeCommandAction), + new PropertyMetadata(null)); + + /// + /// Identifies the dependency property. /// - public sealed class InvokeCommandAction : DependencyObject, IAction + [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] + public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register( + "CommandParameter", + typeof(object), + typeof(InvokeCommandAction), + new PropertyMetadata(null)); + + /// + /// Identifies the dependency property. + /// + [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] + public static readonly DependencyProperty InputConverterProperty = DependencyProperty.Register( + "InputConverter", + typeof(IValueConverter), + typeof(InvokeCommandAction), + new PropertyMetadata(null)); + + /// + /// Identifies the dependency property. + /// + [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] + public static readonly DependencyProperty InputConverterParameterProperty = DependencyProperty.Register( + "InputConverterParameter", + typeof(object), + typeof(InvokeCommandAction), + new PropertyMetadata(null)); + + /// + /// Identifies the dependency property. + /// + [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] + public static readonly DependencyProperty InputConverterLanguageProperty = DependencyProperty.Register( + "InputConverterLanguage", + typeof(string), + typeof(InvokeCommandAction), + new PropertyMetadata(string.Empty)); // Empty string means the invariant culture. + + /// + /// Gets or sets the command this action should invoke. This is a dependency property. + /// + public ICommand Command { - /// - /// Identifies the dependency property. - /// - [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] - public static readonly DependencyProperty CommandProperty = DependencyProperty.Register( - "Command", - typeof(ICommand), - typeof(InvokeCommandAction), - new PropertyMetadata(null)); - - /// - /// Identifies the dependency property. - /// - [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] - public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register( - "CommandParameter", - typeof(object), - typeof(InvokeCommandAction), - new PropertyMetadata(null)); - - /// - /// Identifies the dependency property. - /// - [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] - public static readonly DependencyProperty InputConverterProperty = DependencyProperty.Register( - "InputConverter", - typeof(IValueConverter), - typeof(InvokeCommandAction), - new PropertyMetadata(null)); - - /// - /// Identifies the dependency property. - /// - [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] - public static readonly DependencyProperty InputConverterParameterProperty = DependencyProperty.Register( - "InputConverterParameter", - typeof(object), - typeof(InvokeCommandAction), - new PropertyMetadata(null)); - - /// - /// Identifies the dependency property. - /// - [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] - public static readonly DependencyProperty InputConverterLanguageProperty = DependencyProperty.Register( - "InputConverterLanguage", - typeof(string), - typeof(InvokeCommandAction), - new PropertyMetadata(string.Empty)); // Empty string means the invariant culture. - - /// - /// Gets or sets the command this action should invoke. This is a dependency property. - /// - public ICommand Command + get + { + return (ICommand)this.GetValue(InvokeCommandAction.CommandProperty); + } + set { - get - { - return (ICommand)this.GetValue(InvokeCommandAction.CommandProperty); - } - set - { - this.SetValue(InvokeCommandAction.CommandProperty, value); - } + this.SetValue(InvokeCommandAction.CommandProperty, value); } + } - /// - /// Gets or sets the parameter that is passed to . - /// If this is not set, the parameter from the method will be used. - /// This is an optional dependency property. - /// - public object CommandParameter + /// + /// Gets or sets the parameter that is passed to . + /// If this is not set, the parameter from the method will be used. + /// This is an optional dependency property. + /// + public object CommandParameter + { + get { - get - { - return this.GetValue(InvokeCommandAction.CommandParameterProperty); - } - set - { - this.SetValue(InvokeCommandAction.CommandParameterProperty, value); - } + return this.GetValue(InvokeCommandAction.CommandParameterProperty); } + set + { + this.SetValue(InvokeCommandAction.CommandParameterProperty, value); + } + } - /// - /// Gets or sets the converter that is run on the parameter from the method. - /// This is an optional dependency property. - /// - public IValueConverter InputConverter + /// + /// Gets or sets the converter that is run on the parameter from the method. + /// This is an optional dependency property. + /// + public IValueConverter InputConverter + { + get { - get - { - return (IValueConverter)this.GetValue(InvokeCommandAction.InputConverterProperty); - } - set - { - this.SetValue(InvokeCommandAction.InputConverterProperty, value); - } + return (IValueConverter)this.GetValue(InvokeCommandAction.InputConverterProperty); } + set + { + this.SetValue(InvokeCommandAction.InputConverterProperty, value); + } + } + + /// + /// Gets or sets the parameter that is passed to the + /// method of . + /// This is an optional dependency property. + /// + public object InputConverterParameter + { + get + { + return this.GetValue(InvokeCommandAction.InputConverterParameterProperty); + } + set + { + this.SetValue(InvokeCommandAction.InputConverterParameterProperty, value); + } + } + + /// + /// Gets or sets the language that is passed to the + /// method of . + /// This is an optional dependency property. + /// + public string InputConverterLanguage + { + get + { + return (string)this.GetValue(InvokeCommandAction.InputConverterLanguageProperty); + } + set + { + this.SetValue(InvokeCommandAction.InputConverterLanguageProperty, value); + } + } - /// - /// Gets or sets the parameter that is passed to the - /// method of . - /// This is an optional dependency property. - /// - public object InputConverterParameter + /// + /// Executes the action. + /// + /// The that is passed to the action by the behavior. Generally this is or a target object. + /// The value of this parameter is determined by the caller. + /// True if the command is successfully executed; else false. + public object Execute(object sender, object parameter) + { + if (this.Command == null) { - get - { - return this.GetValue(InvokeCommandAction.InputConverterParameterProperty); - } - set - { - this.SetValue(InvokeCommandAction.InputConverterParameterProperty, value); - } + return false; } - /// - /// Gets or sets the language that is passed to the - /// method of . - /// This is an optional dependency property. - /// - public string InputConverterLanguage + object resolvedParameter; + if (this.ReadLocalValue(InvokeCommandAction.CommandParameterProperty) != DependencyProperty.UnsetValue) + { + resolvedParameter = this.CommandParameter; + } + else if (this.InputConverter != null) { - get - { - return (string)this.GetValue(InvokeCommandAction.InputConverterLanguageProperty); - } - set - { - this.SetValue(InvokeCommandAction.InputConverterLanguageProperty, value); - } + resolvedParameter = this.InputConverter.Convert( + parameter, + typeof(object), + this.InputConverterParameter, + this.InputConverterLanguage); + } + else + { + resolvedParameter = parameter; } - /// - /// Executes the action. - /// - /// The that is passed to the action by the behavior. Generally this is or a target object. - /// The value of this parameter is determined by the caller. - /// True if the command is successfully executed; else false. - public object Execute(object sender, object parameter) + if (!this.Command.CanExecute(resolvedParameter)) { - if (this.Command == null) - { - return false; - } - - object resolvedParameter; - if (this.ReadLocalValue(InvokeCommandAction.CommandParameterProperty) != DependencyProperty.UnsetValue) - { - resolvedParameter = this.CommandParameter; - } - else if (this.InputConverter != null) - { - resolvedParameter = this.InputConverter.Convert( - parameter, - typeof(object), - this.InputConverterParameter, - this.InputConverterLanguage); - } - else - { - resolvedParameter = parameter; - } - - if (!this.Command.CanExecute(resolvedParameter)) - { - return false; - } - - this.Command.Execute(resolvedParameter); - return true; + return false; } + + this.Command.Execute(resolvedParameter); + return true; } } diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/NavigateToPageAction.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/NavigateToPageAction.cs index 66afb15..9d86693 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/NavigateToPageAction.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/NavigateToPageAction.cs @@ -15,151 +15,150 @@ using Windows.UI.Xaml.Markup; #endif -namespace Microsoft.Xaml.Interactivity +namespace Microsoft.Xaml.Interactivity; + +/// +/// An action that switches the current visual to the specified . +/// +public sealed class NavigateToPageAction : DependencyObject, IAction { + private readonly IVisualTreeHelper _visualTreeHelper; + + /// + /// Identifies the dependency property. + /// + [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] + public static readonly DependencyProperty TargetPageProperty = DependencyProperty.Register( + "TargetPage", + typeof(string), + typeof(NavigateToPageAction), + new PropertyMetadata(null)); + + /// + /// Identifies the dependency property. + /// + [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] + public static readonly DependencyProperty ParameterProperty = DependencyProperty.Register( + "Parameter", + typeof(object), + typeof(NavigateToPageAction), + new PropertyMetadata(null)); + + /// + /// Initializes a new instance of the NavigateToPageAction class. + /// + public NavigateToPageAction() + : this(new UwpVisualTreeHelper()) + { + } + + /// + /// Initializes a new instance of the NavigateToPageAction class. + /// + /// + /// IVisualTreeHelper implementation to use when searching the tree for an + /// INavigate target. + /// + internal NavigateToPageAction(IVisualTreeHelper visualTreeHelper) + { + this._visualTreeHelper = visualTreeHelper; + } + /// - /// An action that switches the current visual to the specified . + /// Gets or sets the fully qualified name of the to navigate to. This is a dependency property. /// - public sealed class NavigateToPageAction : DependencyObject, IAction + public string TargetPage { - private readonly IVisualTreeHelper _visualTreeHelper; - - /// - /// Identifies the dependency property. - /// - [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] - public static readonly DependencyProperty TargetPageProperty = DependencyProperty.Register( - "TargetPage", - typeof(string), - typeof(NavigateToPageAction), - new PropertyMetadata(null)); - - /// - /// Identifies the dependency property. - /// - [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] - public static readonly DependencyProperty ParameterProperty = DependencyProperty.Register( - "Parameter", - typeof(object), - typeof(NavigateToPageAction), - new PropertyMetadata(null)); - - /// - /// Initializes a new instance of the NavigateToPageAction class. - /// - public NavigateToPageAction() - : this(new UwpVisualTreeHelper()) + get { + return (string)this.GetValue(NavigateToPageAction.TargetPageProperty); } - - /// - /// Initializes a new instance of the NavigateToPageAction class. - /// - /// - /// IVisualTreeHelper implementation to use when searching the tree for an - /// INavigate target. - /// - internal NavigateToPageAction(IVisualTreeHelper visualTreeHelper) + set { - this._visualTreeHelper = visualTreeHelper; + this.SetValue(NavigateToPageAction.TargetPageProperty, value); } + } - /// - /// Gets or sets the fully qualified name of the to navigate to. This is a dependency property. - /// - public string TargetPage + /// + /// Gets or sets the parameter which will be passed to the method. + /// + public object Parameter + { + get { - get - { - return (string)this.GetValue(NavigateToPageAction.TargetPageProperty); - } - set - { - this.SetValue(NavigateToPageAction.TargetPageProperty, value); - } + return (object)this.GetValue(NavigateToPageAction.ParameterProperty); } - - /// - /// Gets or sets the parameter which will be passed to the method. - /// - public object Parameter + set { - get - { - return (object)this.GetValue(NavigateToPageAction.ParameterProperty); - } - set - { - this.SetValue(NavigateToPageAction.ParameterProperty, value); - } + this.SetValue(NavigateToPageAction.ParameterProperty, value); } + } - /// - /// Executes the action. - /// - /// The that is passed to the action by the behavior. Generally this is or a target object. - /// The value of this parameter is determined by the caller. - /// True if the navigation to the specified page is successful; else false. - public object Execute(object sender, object parameter) + /// + /// Executes the action. + /// + /// The that is passed to the action by the behavior. Generally this is or a target object. + /// The value of this parameter is determined by the caller. + /// True if the navigation to the specified page is successful; else false. + public object Execute(object sender, object parameter) + { + if (string.IsNullOrEmpty(this.TargetPage)) { - if (string.IsNullOrEmpty(this.TargetPage)) - { - return false; - } - - IXamlMetadataProvider metadataProvider = Application.Current as IXamlMetadataProvider; - if (metadataProvider == null) - { - // This will happen if there are no XAML files in the project other than App.xaml. - // The markup compiler doesn't bother implementing IXamlMetadataProvider on the app - // in that case. - return false; - } + return false; + } - IXamlType xamlType = metadataProvider.GetXamlType(this.TargetPage); - if (xamlType == null) - { - return false; - } + IXamlMetadataProvider metadataProvider = Application.Current as IXamlMetadataProvider; + if (metadataProvider == null) + { + // This will happen if there are no XAML files in the project other than App.xaml. + // The markup compiler doesn't bother implementing IXamlMetadataProvider on the app + // in that case. + return false; + } - INavigate navigateElement; - if (sender is UIElement element && element.XamlRoot != null) - { - navigateElement = element.XamlRoot.Content as INavigate; - } - else - { - navigateElement = Window.Current?.Content as INavigate; - } + IXamlType xamlType = metadataProvider.GetXamlType(this.TargetPage); + if (xamlType == null) + { + return false; + } - DependencyObject senderObject = sender as DependencyObject; + INavigate navigateElement; + if (sender is UIElement element && element.XamlRoot != null) + { + navigateElement = element.XamlRoot.Content as INavigate; + } + else + { + navigateElement = Window.Current?.Content as INavigate; + } - // If the sender wasn't an INavigate, then keep looking up the tree from the - // root we were given for another INavigate. - while (senderObject != null && navigateElement == null) - { - navigateElement = senderObject as INavigate; - if (navigateElement == null) - { - senderObject = this._visualTreeHelper.GetParent(senderObject); - } - } + DependencyObject senderObject = sender as DependencyObject; + // If the sender wasn't an INavigate, then keep looking up the tree from the + // root we were given for another INavigate. + while (senderObject != null && navigateElement == null) + { + navigateElement = senderObject as INavigate; if (navigateElement == null) { - return false; + senderObject = this._visualTreeHelper.GetParent(senderObject); } + } - Frame frame = navigateElement as Frame; + if (navigateElement == null) + { + return false; + } - if (frame != null) - { - return frame.Navigate(xamlType.UnderlyingType, this.Parameter ?? parameter); - } - else - { - return navigateElement.Navigate(xamlType.UnderlyingType); - } + Frame frame = navigateElement as Frame; + + if (frame != null) + { + return frame.Navigate(xamlType.UnderlyingType, this.Parameter ?? parameter); + } + else + { + return navigateElement.Navigate(xamlType.UnderlyingType); } } } diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ResourceHelper.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ResourceHelper.cs index 06f7989..2c6b0c7 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ResourceHelper.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/ResourceHelper.cs @@ -1,101 +1,101 @@ // 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 class ResourceHelper - { +namespace Microsoft.Xaml.Interactivity; + +using Windows.ApplicationModel.Resources; + +internal static class ResourceHelper +{ #if NET8_0_OR_GREATER && !MODERN_WINDOWS_UWP - private static ResourceLoader strings = new ResourceLoader(ResourceLoader.GetDefaultResourceFilePath(), "Microsoft.Xaml.Interactivity/Strings"); + private static ResourceLoader strings = new ResourceLoader(ResourceLoader.GetDefaultResourceFilePath(), "Microsoft.Xaml.Interactivity/Strings"); #endif - public static string GetString(string resourceName) - { + public static string GetString(string resourceName) + { #if !NET8_0_OR_GREATER || MODERN_WINDOWS_UWP - ResourceLoader strings = ResourceLoader.GetForCurrentView("Microsoft.Xaml.Interactivity/Strings"); + ResourceLoader strings = ResourceLoader.GetForCurrentView("Microsoft.Xaml.Interactivity/Strings"); #endif - return strings.GetString(resourceName); - } + return strings.GetString(resourceName); + } - public static string CallMethodActionValidMethodNotFoundExceptionMessage + public static string CallMethodActionValidMethodNotFoundExceptionMessage + { + get { - get - { - return ResourceHelper.GetString("CallMethodActionValidMethodNotFoundExceptionMessage"); - } + return ResourceHelper.GetString("CallMethodActionValidMethodNotFoundExceptionMessage"); } + } - public static string ChangePropertyActionCannotFindPropertyNameExceptionMessage + public static string ChangePropertyActionCannotFindPropertyNameExceptionMessage + { + get { - get - { - return ResourceHelper.GetString("ChangePropertyActionCannotFindPropertyNameExceptionMessage"); - } + return ResourceHelper.GetString("ChangePropertyActionCannotFindPropertyNameExceptionMessage"); } + } - public static string ChangePropertyActionCannotSetValueExceptionMessage + public static string ChangePropertyActionCannotSetValueExceptionMessage + { + get { - get - { - return ResourceHelper.GetString("ChangePropertyActionCannotSetValueExceptionMessage"); - } + return ResourceHelper.GetString("ChangePropertyActionCannotSetValueExceptionMessage"); } + } - public static string ChangePropertyActionPropertyIsReadOnlyExceptionMessage + public static string ChangePropertyActionPropertyIsReadOnlyExceptionMessage + { + get { - get - { - return ResourceHelper.GetString("ChangePropertyActionPropertyIsReadOnlyExceptionMessage"); - } + return ResourceHelper.GetString("ChangePropertyActionPropertyIsReadOnlyExceptionMessage"); } + } - public static string GoToStateActionTargetHasNoStateGroups + public static string GoToStateActionTargetHasNoStateGroups + { + get { - get - { - return ResourceHelper.GetString("GoToStateActionTargetHasNoStateGroups"); - } + return ResourceHelper.GetString("GoToStateActionTargetHasNoStateGroups"); } + } - public static string CannotAttachBehaviorMultipleTimesExceptionMessage + public static string CannotAttachBehaviorMultipleTimesExceptionMessage + { + get { - get - { - return ResourceHelper.GetString("CannotAttachBehaviorMultipleTimesExceptionMessage"); - } + return ResourceHelper.GetString("CannotAttachBehaviorMultipleTimesExceptionMessage"); } + } - public static string CannotFindEventNameExceptionMessage + public static string CannotFindEventNameExceptionMessage + { + get { - get - { - return ResourceHelper.GetString("CannotFindEventNameExceptionMessage"); - } + return ResourceHelper.GetString("CannotFindEventNameExceptionMessage"); } + } - public static string InvalidLeftOperand + public static string InvalidLeftOperand + { + get { - get - { - return ResourceHelper.GetString("InvalidLeftOperand"); - } + return ResourceHelper.GetString("InvalidLeftOperand"); } + } - public static string InvalidRightOperand + public static string InvalidRightOperand + { + get { - get - { - return ResourceHelper.GetString("InvalidRightOperand"); - } + return ResourceHelper.GetString("InvalidRightOperand"); } + } - public static string InvalidOperands + public static string InvalidOperands + { + get { - get - { - return ResourceHelper.GetString("InvalidOperands"); - } + return ResourceHelper.GetString("InvalidOperands"); } } } diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/TypeConverterHelper.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/TypeConverterHelper.cs index 72d2e8a..2ef36ae 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/TypeConverterHelper.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Core/TypeConverterHelper.cs @@ -12,84 +12,83 @@ using Windows.UI.Xaml.Markup; #endif -namespace Microsoft.Xaml.Interactivity +namespace Microsoft.Xaml.Interactivity; + +/// +/// A helper class that enables converting values specified in markup (strings) to their object representation. +/// +internal static class TypeConverterHelper { + private const string ContentControlFormatString = "{2}"; + /// - /// A helper class that enables converting values specified in markup (strings) to their object representation. + /// Converts string representation of a value to its object representation. /// - internal static class TypeConverterHelper + /// The value to convert. + /// The full name of the destination type. + /// Object representation of the string value. + /// destinationTypeFullName cannot be null. + public static Object Convert(string value, string destinationTypeFullName) { - private const string ContentControlFormatString = "{2}"; + if (string.IsNullOrEmpty(destinationTypeFullName)) + { + throw new ArgumentNullException(nameof(destinationTypeFullName)); + } - /// - /// Converts string representation of a value to its object representation. - /// - /// The value to convert. - /// The full name of the destination type. - /// Object representation of the string value. - /// destinationTypeFullName cannot be null. - public static Object Convert(string value, string destinationTypeFullName) + string scope = TypeConverterHelper.GetScope(destinationTypeFullName); + + // Value types in the "System" namespace must be special cased due to a bug in the xaml compiler + if (string.Equals(scope, "System", StringComparison.Ordinal)) { - if (string.IsNullOrEmpty(destinationTypeFullName)) + if (string.Equals(destinationTypeFullName, (typeof(string).FullName), StringComparison.Ordinal)) { - throw new ArgumentNullException(nameof(destinationTypeFullName)); + return value; } - - string scope = TypeConverterHelper.GetScope(destinationTypeFullName); - - // Value types in the "System" namespace must be special cased due to a bug in the xaml compiler - if (string.Equals(scope, "System", StringComparison.Ordinal)) + else if (string.Equals(destinationTypeFullName, typeof(bool).FullName, StringComparison.Ordinal)) { - if (string.Equals(destinationTypeFullName, (typeof(string).FullName), StringComparison.Ordinal)) - { - return value; - } - else if (string.Equals(destinationTypeFullName, typeof(bool).FullName, StringComparison.Ordinal)) - { - return bool.Parse(value); - } - else if (string.Equals(destinationTypeFullName, typeof(int).FullName, StringComparison.Ordinal)) - { - return int.Parse(value, CultureInfo.InvariantCulture); - } - else if (string.Equals(destinationTypeFullName, typeof(double).FullName, StringComparison.Ordinal)) - { - return double.Parse(value, CultureInfo.InvariantCulture); - } + return bool.Parse(value); } - - string type = TypeConverterHelper.GetType(destinationTypeFullName); - string contentControlXaml = string.Format(CultureInfo.InvariantCulture, TypeConverterHelper.ContentControlFormatString, scope, type, value); - - ContentControl contentControl = XamlReader.Load(contentControlXaml) as ContentControl; - if (contentControl != null) + else if (string.Equals(destinationTypeFullName, typeof(int).FullName, StringComparison.Ordinal)) { - return contentControl.Content; + return int.Parse(value, CultureInfo.InvariantCulture); } - - return null; - } - - private static String GetScope(string name) - { - int indexOfLastPeriod = name.LastIndexOf('.'); - if (indexOfLastPeriod != name.Length - 1) + else if (string.Equals(destinationTypeFullName, typeof(double).FullName, StringComparison.Ordinal)) { - return name.Substring(0, indexOfLastPeriod); + return double.Parse(value, CultureInfo.InvariantCulture); } + } - return name; + string type = TypeConverterHelper.GetType(destinationTypeFullName); + string contentControlXaml = string.Format(CultureInfo.InvariantCulture, TypeConverterHelper.ContentControlFormatString, scope, type, value); + + ContentControl contentControl = XamlReader.Load(contentControlXaml) as ContentControl; + if (contentControl != null) + { + return contentControl.Content; } - private static String GetType(string name) + return null; + } + + private static String GetScope(string name) + { + int indexOfLastPeriod = name.LastIndexOf('.'); + if (indexOfLastPeriod != name.Length - 1) { - int indexOfLastPeriod = name.LastIndexOf('.'); - if (indexOfLastPeriod != name.Length - 1) - { - return name.Substring(++indexOfLastPeriod); - } + return name.Substring(0, indexOfLastPeriod); + } + + return name; + } - return name; + private static String GetType(string name) + { + int indexOfLastPeriod = name.LastIndexOf('.'); + if (indexOfLastPeriod != name.Length - 1) + { + return name.Substring(++indexOfLastPeriod); } + + return name; } } diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/CustomPropertyValueEditorAttribute.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/CustomPropertyValueEditorAttribute.cs index d022328..4191f03 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/CustomPropertyValueEditorAttribute.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/CustomPropertyValueEditorAttribute.cs @@ -3,54 +3,53 @@ using System; -namespace Microsoft.Xaml.Interactivity +namespace Microsoft.Xaml.Interactivity; + +/// +/// Enumerates possible values for reusable property value editors. +/// +public enum CustomPropertyValueEditor +{ + /// + /// Uses the storyboard picker, if supported, to edit this property at design time. + /// + Storyboard, + /// + /// Uses the state picker, if supported, to edit this property at design time. + /// + StateName, + /// + /// Uses the element-binding picker, if supported, to edit this property at design time. + /// + ElementBinding, + /// + /// Uses the property-binding picker, if supported, to edit this property at design time. + /// + PropertyBinding, +} + +/// +/// Associates the given editor type with the property to which the is applied. +/// +/// Use this attribute to get improved design-time editing for properties that denote element (by name), storyboards, or states (by name). +[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] +public sealed class CustomPropertyValueEditorAttribute : Attribute { /// - /// Enumerates possible values for reusable property value editors. + /// Initializes a new instance of the class. /// - public enum CustomPropertyValueEditor + /// The custom property value editor. + public CustomPropertyValueEditorAttribute(CustomPropertyValueEditor customPropertyValueEditor) { - /// - /// Uses the storyboard picker, if supported, to edit this property at design time. - /// - Storyboard, - /// - /// Uses the state picker, if supported, to edit this property at design time. - /// - StateName, - /// - /// Uses the element-binding picker, if supported, to edit this property at design time. - /// - ElementBinding, - /// - /// Uses the property-binding picker, if supported, to edit this property at design time. - /// - PropertyBinding, + this.CustomPropertyValueEditor = customPropertyValueEditor; } /// - /// Associates the given editor type with the property to which the is applied. + /// Gets the custom property value editor. /// - /// Use this attribute to get improved design-time editing for properties that denote element (by name), storyboards, or states (by name). - [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] - public sealed class CustomPropertyValueEditorAttribute : Attribute + public CustomPropertyValueEditor CustomPropertyValueEditor { - /// - /// Initializes a new instance of the class. - /// - /// The custom property value editor. - public CustomPropertyValueEditorAttribute(CustomPropertyValueEditor customPropertyValueEditor) - { - this.CustomPropertyValueEditor = customPropertyValueEditor; - } - - /// - /// Gets the custom property value editor. - /// - public CustomPropertyValueEditor CustomPropertyValueEditor - { - get; - private set; - } + get; + private set; } } \ No newline at end of file diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/DefaultEventAttribute.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/DefaultEventAttribute.cs index 037f4ef..80f7406 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/DefaultEventAttribute.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/DefaultEventAttribute.cs @@ -3,48 +3,47 @@ using System; -namespace Microsoft.Xaml.Interactivity +namespace Microsoft.Xaml.Interactivity; + +/// +/// Provides design tools information about which EventName to set for EventTriggerBehavior when instantiating an . +/// +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public sealed class DefaultEventAttribute : Attribute { + private readonly Type _targetType; + private readonly string _eventName; + /// - /// Provides design tools information about which EventName to set for EventTriggerBehavior when instantiating an . + /// Initializes a new instance of the class. /// - [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] - public sealed class DefaultEventAttribute : Attribute + /// The type this attribute applies to. + /// The event name for the EventTriggerBehavior. + public DefaultEventAttribute(Type targetType, string eventName) { - private readonly Type _targetType; - private readonly string _eventName; - - /// - /// Initializes a new instance of the class. - /// - /// The type this attribute applies to. - /// The event name for the EventTriggerBehavior. - public DefaultEventAttribute(Type targetType, string eventName) - { - this._targetType = targetType; - this._eventName = eventName; - } + this._targetType = targetType; + this._eventName = eventName; + } - /// - /// Gets the type that the applies to. - /// - public Type TargetType + /// + /// Gets the type that the applies to. + /// + public Type TargetType + { + get { - get - { - return this._targetType; - } + return this._targetType; } + } - /// - /// Gets the event name to pass to the EventTriggerBehavior constructor. - /// - public string EventName + /// + /// Gets the event name to pass to the EventTriggerBehavior constructor. + /// + public string EventName + { + get { - get - { - return this._eventName; - } + return this._eventName; } } } \ No newline at end of file diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/IAction.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/IAction.cs index c93e966..e3c3302 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/IAction.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/IAction.cs @@ -1,19 +1,19 @@ // 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 + +namespace Microsoft.Xaml.Interactivity; + +/// +/// Interface implemented by all custom actions. +/// +public interface IAction { /// - /// Interface implemented by all custom actions. + /// Executes the action. /// - public interface IAction - { - /// - /// Executes the action. - /// - /// The that is passed to the action by the behavior. Generally this is or a target object. - /// The value of this parameter is determined by the caller. - /// An example of parameter usage is EventTriggerBehavior, which passes the EventArgs as a parameter to its actions. - /// Returns the result of the action. - object Execute(object sender, object parameter); - } + /// The that is passed to the action by the behavior. Generally this is or a target object. + /// The value of this parameter is determined by the caller. + /// An example of parameter usage is EventTriggerBehavior, which passes the EventArgs as a parameter to its actions. + /// Returns the result of the action. + object Execute(object sender, object parameter); } diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/IBehavior.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/IBehavior.cs index db5b77d..2925ffd 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/IBehavior.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/IBehavior.cs @@ -7,30 +7,29 @@ using Windows.UI.Xaml; #endif -namespace Microsoft.Xaml.Interactivity +namespace Microsoft.Xaml.Interactivity; + +/// +/// Interface implemented by all custom behaviors. +/// +public interface IBehavior { /// - /// Interface implemented by all custom behaviors. + /// Gets the to which the is attached. /// - public interface IBehavior + DependencyObject AssociatedObject { - /// - /// Gets the to which the is attached. - /// - DependencyObject AssociatedObject - { - get; - } + get; + } - /// - /// Attaches to the specified object. - /// - /// The to which the will be attached. - void Attach(DependencyObject associatedObject); + /// + /// Attaches to the specified object. + /// + /// The to which the will be attached. + void Attach(DependencyObject associatedObject); - /// - /// Detaches this instance from its associated object. - /// - void Detach(); - } + /// + /// Detaches this instance from its associated object. + /// + void Detach(); } diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/ITrigger.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/ITrigger.cs index cb22b16..b5b25d0 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/ITrigger.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/ITrigger.cs @@ -1,15 +1,15 @@ // 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 + +namespace Microsoft.Xaml.Interactivity; + +/// +/// Interface implemented by all custom triggers. +/// +public interface ITrigger : IBehavior { /// - /// Interface implemented by all custom triggers. + /// Gets the collection of actions associated with the behavior. /// - public interface ITrigger : IBehavior - { - /// - /// Gets the collection of actions associated with the behavior. - /// - ActionCollection Actions { get; } - } + ActionCollection Actions { get; } } \ No newline at end of file diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Interaction.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Interaction.cs index 945716f..a5ef5af 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Interaction.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Interaction.cs @@ -11,139 +11,138 @@ using Windows.UI.Xaml; #endif -namespace Microsoft.Xaml.Interactivity +namespace Microsoft.Xaml.Interactivity; + +/// +/// Defines a attached property and provides a method for executing an . +/// +public sealed class Interaction { + /// + /// CA1053: Static holder types should not have public constructors + /// + private Interaction() + { + } + + /// + /// Gets or sets the associated with a specified object. + /// + [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] + public static readonly DependencyProperty BehaviorsProperty = DependencyProperty.RegisterAttached( + "Behaviors", + typeof(BehaviorCollection), + typeof(Interaction), + new PropertyMetadata(null, new PropertyChangedCallback(Interaction.OnBehaviorsChanged))); + /// - /// Defines a attached property and provides a method for executing an . + /// Gets the associated with a specified object. /// - public sealed class Interaction + /// The from which to retrieve the . + /// A containing the behaviors associated with the specified object. + public static BehaviorCollection GetBehaviors(DependencyObject obj) { - /// - /// CA1053: Static holder types should not have public constructors - /// - private Interaction() + if (obj == null) { + throw new ArgumentNullException(nameof(obj)); } - - /// - /// Gets or sets the associated with a specified object. - /// - [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] - public static readonly DependencyProperty BehaviorsProperty = DependencyProperty.RegisterAttached( - "Behaviors", - typeof(BehaviorCollection), - typeof(Interaction), - new PropertyMetadata(null, new PropertyChangedCallback(Interaction.OnBehaviorsChanged))); - - /// - /// Gets the associated with a specified object. - /// - /// The from which to retrieve the . - /// A containing the behaviors associated with the specified object. - public static BehaviorCollection GetBehaviors(DependencyObject obj) + BehaviorCollection behaviorCollection = (BehaviorCollection)obj.GetValue(Interaction.BehaviorsProperty); + if (behaviorCollection == null) { - if (obj == null) - { - throw new ArgumentNullException(nameof(obj)); - } - BehaviorCollection behaviorCollection = (BehaviorCollection)obj.GetValue(Interaction.BehaviorsProperty); - if (behaviorCollection == null) - { - behaviorCollection = new BehaviorCollection(); - obj.SetValue(Interaction.BehaviorsProperty, behaviorCollection); - - var frameworkElement = obj as FrameworkElement; - - if (frameworkElement != null) - { - frameworkElement.Loaded -= FrameworkElement_Loaded; - frameworkElement.Loaded += FrameworkElement_Loaded; - frameworkElement.Unloaded -= FrameworkElement_Unloaded; - frameworkElement.Unloaded += FrameworkElement_Unloaded; - } - } + behaviorCollection = new BehaviorCollection(); + obj.SetValue(Interaction.BehaviorsProperty, behaviorCollection); - return behaviorCollection; - } + var frameworkElement = obj as FrameworkElement; - /// - /// Sets the associated with a specified object. - /// - /// The on which to set the . - /// The associated with the object. - public static void SetBehaviors(DependencyObject obj, BehaviorCollection value) - { - if (obj == null) + if (frameworkElement != null) { - throw new ArgumentNullException(nameof(obj)); + frameworkElement.Loaded -= FrameworkElement_Loaded; + frameworkElement.Loaded += FrameworkElement_Loaded; + frameworkElement.Unloaded -= FrameworkElement_Unloaded; + frameworkElement.Unloaded += FrameworkElement_Unloaded; } - obj.SetValue(Interaction.BehaviorsProperty, value); } - /// - /// Executes all actions in the and returns their results. - /// - /// The which will be passed on to the action. - /// The set of actions to execute. - /// The value of this parameter is determined by the calling behavior. - /// Returns the results of the actions. - public static IEnumerable ExecuteActions(object sender, ActionCollection actions, object parameter) - { - List results = new List(); + return behaviorCollection; + } - if (actions == null || global::Windows.ApplicationModel.DesignMode.DesignModeEnabled) - { - return results; - } + /// + /// Sets the associated with a specified object. + /// + /// The on which to set the . + /// The associated with the object. + public static void SetBehaviors(DependencyObject obj, BehaviorCollection value) + { + if (obj == null) + { + throw new ArgumentNullException(nameof(obj)); + } + obj.SetValue(Interaction.BehaviorsProperty, value); + } - foreach (DependencyObject dependencyObject in actions) - { - IAction action = (IAction)dependencyObject; - results.Add(action.Execute(sender, parameter)); - } + /// + /// Executes all actions in the and returns their results. + /// + /// The which will be passed on to the action. + /// The set of actions to execute. + /// The value of this parameter is determined by the calling behavior. + /// Returns the results of the actions. + public static IEnumerable ExecuteActions(object sender, ActionCollection actions, object parameter) + { + List results = new List(); + if (actions == null || global::Windows.ApplicationModel.DesignMode.DesignModeEnabled) + { return results; } - private static void OnBehaviorsChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args) + foreach (DependencyObject dependencyObject in actions) { - BehaviorCollection oldCollection = (BehaviorCollection)args.OldValue; - BehaviorCollection newCollection = (BehaviorCollection)args.NewValue; + IAction action = (IAction)dependencyObject; + results.Add(action.Execute(sender, parameter)); + } - if (oldCollection == newCollection) - { - return; - } + return results; + } - if (oldCollection != null && oldCollection.AssociatedObject != null) - { - oldCollection.Detach(); - } + private static void OnBehaviorsChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args) + { + BehaviorCollection oldCollection = (BehaviorCollection)args.OldValue; + BehaviorCollection newCollection = (BehaviorCollection)args.NewValue; - if (newCollection != null && sender != null) - { - newCollection.Attach(sender); - } + if (oldCollection == newCollection) + { + return; } - private static void FrameworkElement_Loaded(object sender, RoutedEventArgs e) + if (oldCollection != null && oldCollection.AssociatedObject != null) { - var d = sender as DependencyObject; + oldCollection.Detach(); + } - if (d != null) - { - GetBehaviors(d).Attach(d); - } + if (newCollection != null && sender != null) + { + newCollection.Attach(sender); } + } - private static void FrameworkElement_Unloaded(object sender, RoutedEventArgs e) + private static void FrameworkElement_Loaded(object sender, RoutedEventArgs e) + { + var d = sender as DependencyObject; + + if (d != null) { - var d = sender as DependencyObject; + GetBehaviors(d).Attach(d); + } + } - if (d != null) - { - GetBehaviors(d).Detach(); - } + private static void FrameworkElement_Unloaded(object sender, RoutedEventArgs e) + { + var d = sender as DependencyObject; + + if (d != null) + { + GetBehaviors(d).Detach(); } } } \ No newline at end of file diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Media/ControlStoryboardAction.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Media/ControlStoryboardAction.cs index 4945603..e340935 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Media/ControlStoryboardAction.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Media/ControlStoryboardAction.cs @@ -11,155 +11,154 @@ using Windows.UI.Xaml.Media.Animation; #endif -namespace Microsoft.Xaml.Interactivity -{ +namespace Microsoft.Xaml.Interactivity; + #if WinUI +/// +/// An action that will change the state of the specified when executed. +/// +#else +/// +/// An action that will change the state of the specified when executed. +/// +#endif +public sealed class ControlStoryboardAction : DependencyObject, IAction +{ /// - /// An action that will change the state of the specified when executed. + /// Identifies the dependency property. /// -#else + [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] + public static readonly DependencyProperty ControlStoryboardOptionProperty = DependencyProperty.Register( + "ControlStoryboardOption", + typeof(ControlStoryboardOption), + typeof(ControlStoryboardAction), + new PropertyMetadata(ControlStoryboardOption.Play)); + /// - /// An action that will change the state of the specified when executed. + /// Identifies the dependency property. /// -#endif - public sealed class ControlStoryboardAction : DependencyObject, IAction - { - /// - /// Identifies the dependency property. - /// - [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] - public static readonly DependencyProperty ControlStoryboardOptionProperty = DependencyProperty.Register( - "ControlStoryboardOption", - typeof(ControlStoryboardOption), - typeof(ControlStoryboardAction), - new PropertyMetadata(ControlStoryboardOption.Play)); - - /// - /// Identifies the dependency property. - /// - [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] - public static readonly DependencyProperty StoryboardProperty = DependencyProperty.Register( - "Storyboard", - typeof(Storyboard), - typeof(ControlStoryboardAction), - new PropertyMetadata(null, new PropertyChangedCallback(ControlStoryboardAction.OnStoryboardChanged))); - - private bool _isPaused; + [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] + public static readonly DependencyProperty StoryboardProperty = DependencyProperty.Register( + "Storyboard", + typeof(Storyboard), + typeof(ControlStoryboardAction), + new PropertyMetadata(null, new PropertyChangedCallback(ControlStoryboardAction.OnStoryboardChanged))); + + private bool _isPaused; #if WinUI - /// - /// Gets or sets the action to execute on the . This is a dependency property. - /// + /// + /// Gets or sets the action to execute on the . This is a dependency property. + /// #else - /// - /// Gets or sets the action to execute on the . This is a dependency property. - /// + /// + /// Gets or sets the action to execute on the . This is a dependency property. + /// #endif - public ControlStoryboardOption ControlStoryboardOption - { - get - { - return (ControlStoryboardOption)this.GetValue(ControlStoryboardAction.ControlStoryboardOptionProperty); - } - set - { - this.SetValue(ControlStoryboardAction.ControlStoryboardOptionProperty, value); - } - } + public ControlStoryboardOption ControlStoryboardOption + { + get + { + return (ControlStoryboardOption)this.GetValue(ControlStoryboardAction.ControlStoryboardOptionProperty); + } + set + { + this.SetValue(ControlStoryboardAction.ControlStoryboardOptionProperty, value); + } + } #if WinUI - /// - /// Gets or sets the targeted . This is a dependency property. - /// + /// + /// Gets or sets the targeted . This is a dependency property. + /// #else - /// - /// Gets or sets the targeted . This is a dependency property. - /// + /// + /// Gets or sets the targeted . This is a dependency property. + /// #endif - public Storyboard Storyboard - { - get - { - return (Storyboard)this.GetValue(ControlStoryboardAction.StoryboardProperty); - } - set - { - this.SetValue(ControlStoryboardAction.StoryboardProperty, value); - } - } - - /// - /// Executes the action. - /// - /// The that is passed to the action by the behavior. Generally this is or a target object. - /// The value of this parameter is determined by the caller. - /// True if the specified operation is invoked successfully; else false. - public object Execute(object sender, object parameter) - { - if (this.Storyboard == null) - { - return false; - } - - switch (this.ControlStoryboardOption) - { - case ControlStoryboardOption.Play: - this.Storyboard.Begin(); - break; - - case ControlStoryboardOption.Stop: - this.Storyboard.Stop(); - break; - - case ControlStoryboardOption.TogglePlayPause: - { - ClockState currentState = this.Storyboard.GetCurrentState(); - - if (currentState == ClockState.Stopped) - { - this._isPaused = false; - this.Storyboard.Begin(); - } - else if (this._isPaused) - { - this._isPaused = false; - this.Storyboard.Resume(); - } - else - { - this._isPaused = true; - this.Storyboard.Pause(); - } - } - - break; - - case ControlStoryboardOption.Pause: - this.Storyboard.Pause(); - break; - - case ControlStoryboardOption.Resume: - this.Storyboard.Resume(); - break; - - case ControlStoryboardOption.SkipToFill: - this.Storyboard.SkipToFill(); - break; - - default: - return false; - } - - return true; - } - - private static void OnStoryboardChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args) - { - ControlStoryboardAction action = sender as ControlStoryboardAction; - if (action != null) - { - action._isPaused = false; - } - } - } + public Storyboard Storyboard + { + get + { + return (Storyboard)this.GetValue(ControlStoryboardAction.StoryboardProperty); + } + set + { + this.SetValue(ControlStoryboardAction.StoryboardProperty, value); + } + } + + /// + /// Executes the action. + /// + /// The that is passed to the action by the behavior. Generally this is or a target object. + /// The value of this parameter is determined by the caller. + /// True if the specified operation is invoked successfully; else false. + public object Execute(object sender, object parameter) + { + if (this.Storyboard == null) + { + return false; + } + + switch (this.ControlStoryboardOption) + { + case ControlStoryboardOption.Play: + this.Storyboard.Begin(); + break; + + case ControlStoryboardOption.Stop: + this.Storyboard.Stop(); + break; + + case ControlStoryboardOption.TogglePlayPause: + { + ClockState currentState = this.Storyboard.GetCurrentState(); + + if (currentState == ClockState.Stopped) + { + this._isPaused = false; + this.Storyboard.Begin(); + } + else if (this._isPaused) + { + this._isPaused = false; + this.Storyboard.Resume(); + } + else + { + this._isPaused = true; + this.Storyboard.Pause(); + } + } + + break; + + case ControlStoryboardOption.Pause: + this.Storyboard.Pause(); + break; + + case ControlStoryboardOption.Resume: + this.Storyboard.Resume(); + break; + + case ControlStoryboardOption.SkipToFill: + this.Storyboard.SkipToFill(); + break; + + default: + return false; + } + + return true; + } + + private static void OnStoryboardChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args) + { + ControlStoryboardAction action = sender as ControlStoryboardAction; + if (action != null) + { + action._isPaused = false; + } + } } diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Media/ControlStoryboardOption.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Media/ControlStoryboardOption.cs index a4847be..ceb1bd5 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Media/ControlStoryboardOption.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Media/ControlStoryboardOption.cs @@ -6,36 +6,35 @@ // 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 +namespace Microsoft.Xaml.Interactivity; + +/// +/// Represents operations that can be applied to . +/// +public enum ControlStoryboardOption { /// - /// Represents operations that can be applied to . + /// Specifies the play operation. + /// + Play, + /// + /// Specifies the stop operation. + /// + Stop, + /// + /// Specifies the TogglePlayPause operation. + /// + TogglePlayPause, + /// + /// Specifies the pause operation. + /// + Pause, + /// + /// Specifies the resume operation. + /// + Resume, + /// + /// Specifies the SkipToFill operation. /// - public enum ControlStoryboardOption - { - /// - /// Specifies the play operation. - /// - Play, - /// - /// Specifies the stop operation. - /// - Stop, - /// - /// Specifies the TogglePlayPause operation. - /// - TogglePlayPause, - /// - /// Specifies the pause operation. - /// - Pause, - /// - /// Specifies the resume operation. - /// - Resume, - /// - /// Specifies the SkipToFill operation. - /// - SkipToFill - } + SkipToFill } diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Media/PlaySoundAction.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Media/PlaySoundAction.cs index f4900e0..60a700c 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Media/PlaySoundAction.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Media/PlaySoundAction.cs @@ -21,158 +21,157 @@ using Windows.UI.Xaml.Controls.Primitives; #endif -namespace Microsoft.Xaml.Interactivity -{ - /// - /// An action that will play a sound to completion. - /// - /// - /// This action is intended for use with short sound effects that don't need to be stopped or controlled. If you are trying - /// to create a music player or game, it may not meet your needs. - /// - public sealed class PlaySoundAction : DependencyObject, IAction - { - private readonly DispatcherQueue _queue = DispatcherQueue.GetForCurrentThread(); - - private const string MsAppXSchemeFormatString = "ms-appx:///{0}"; - - /// - /// Identifies the dependency property. - /// - [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] - public static readonly DependencyProperty SourceProperty = DependencyProperty.Register( - nameof(Source), - typeof(string), - typeof(PlaySoundAction), - new PropertyMetadata(null)); - - /// - /// Identifies the dependency property. - /// - [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] - public static readonly DependencyProperty VolumeProperty = DependencyProperty.Register( - nameof(Volume), - typeof(double), - typeof(PlaySoundAction), - new PropertyMetadata(0.5)); - - private Popup _popup; - - /// - /// Gets or sets the location of the sound file. This is used to set the source property of a . This is a dependency property. - /// - /// - /// The sound can be any file format supported by . In the case of a video, it will play only the - /// audio portion. - /// - public string Source - { - get - { - return (string)this.GetValue(SourceProperty); - } - set - { - this.SetValue(SourceProperty, value); - } - } - - /// - /// Gets or set the volume of the sound. This is used to set the property of the . This is a dependency property. - /// - /// - /// By default this is set to 0.5. - /// - public double Volume - { - get - { - return (double)this.GetValue(VolumeProperty); - } - set - { - this.SetValue(VolumeProperty, value); - } - } - - /// - /// Executes the action. - /// - /// The that is passed to the action by the behavior. Generally this is or a target object. - /// The value of this parameter is determined by the caller. - /// True if is set successfully; else false. - public object Execute(object sender, object parameter) - { - if (string.IsNullOrEmpty(this.Source)) - { - return false; - } - - Uri sourceUri; - if (!Uri.TryCreate(this.Source, UriKind.Absolute, out sourceUri)) - { - // Impose ms-appx:// scheme if user has specified a relative URI - string absoluteSource = string.Format(CultureInfo.InvariantCulture, MsAppXSchemeFormatString, this.Source); - if (!Uri.TryCreate(absoluteSource, UriKind.Absolute, out sourceUri)) - { - return false; - } - } - - _popup = new Popup(); - if (sender is UIElement element && element.XamlRoot != null) - { - _popup.XamlRoot = element.XamlRoot; - } - - MediaPlayerElement mediaElement = new MediaPlayerElement(); - _popup.Child = mediaElement; - - // It is legal (although not advisable) to provide a video file. By setting visibility to collapsed, only the sound track should play. - mediaElement.Visibility = Visibility.Collapsed; - - mediaElement.Source = MediaSource.CreateFromUri(sourceUri); - mediaElement.AutoPlay = true; - mediaElement.MediaPlayer.Volume = this.Volume; - mediaElement.MediaPlayer.MediaEnded += this.MediaElement_MediaEnded; - mediaElement.MediaPlayer.MediaFailed += this.MediaPlayer_MediaFailed; - - this._popup.IsOpen = true; - return true; - } - - private void MediaPlayer_MediaFailed(MediaPlayer sender, MediaPlayerFailedEventArgs args) - { - // TODO: We should probably have some system/properties to report/bubble errors here - ClosePopup(); - } - - private void MediaElement_MediaEnded(MediaPlayer sender, object args) +namespace Microsoft.Xaml.Interactivity; + +/// +/// An action that will play a sound to completion. +/// +/// +/// This action is intended for use with short sound effects that don't need to be stopped or controlled. If you are trying +/// to create a music player or game, it may not meet your needs. +/// +public sealed class PlaySoundAction : DependencyObject, IAction +{ + private readonly DispatcherQueue _queue = DispatcherQueue.GetForCurrentThread(); + + private const string MsAppXSchemeFormatString = "ms-appx:///{0}"; + + /// + /// Identifies the dependency property. + /// + [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] + public static readonly DependencyProperty SourceProperty = DependencyProperty.Register( + nameof(Source), + typeof(string), + typeof(PlaySoundAction), + new PropertyMetadata(null)); + + /// + /// Identifies the dependency property. + /// + [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] + public static readonly DependencyProperty VolumeProperty = DependencyProperty.Register( + nameof(Volume), + typeof(double), + typeof(PlaySoundAction), + new PropertyMetadata(0.5)); + + private Popup _popup; + + /// + /// Gets or sets the location of the sound file. This is used to set the source property of a . This is a dependency property. + /// + /// + /// The sound can be any file format supported by . In the case of a video, it will play only the + /// audio portion. + /// + public string Source + { + get + { + return (string)this.GetValue(SourceProperty); + } + set { - ClosePopup(); - } + this.SetValue(SourceProperty, value); + } + } + + /// + /// Gets or set the volume of the sound. This is used to set the property of the . This is a dependency property. + /// + /// + /// By default this is set to 0.5. + /// + public double Volume + { + get + { + return (double)this.GetValue(VolumeProperty); + } + set + { + this.SetValue(VolumeProperty, value); + } + } + + /// + /// Executes the action. + /// + /// The that is passed to the action by the behavior. Generally this is or a target object. + /// The value of this parameter is determined by the caller. + /// True if is set successfully; else false. + public object Execute(object sender, object parameter) + { + if (string.IsNullOrEmpty(this.Source)) + { + return false; + } - private void ClosePopup() + Uri sourceUri; + if (!Uri.TryCreate(this.Source, UriKind.Absolute, out sourceUri)) { - void closePopupImpl() + // Impose ms-appx:// scheme if user has specified a relative URI + string absoluteSource = string.Format(CultureInfo.InvariantCulture, MsAppXSchemeFormatString, this.Source); + if (!Uri.TryCreate(absoluteSource, UriKind.Absolute, out sourceUri)) { - if (this._popup != null) - { - this._popup.IsOpen = false; - this._popup.Child = null; - this._popup = null; - } + return false; } + } - if (_queue.HasThreadAccess) + _popup = new Popup(); + if (sender is UIElement element && element.XamlRoot != null) + { + _popup.XamlRoot = element.XamlRoot; + } + + MediaPlayerElement mediaElement = new MediaPlayerElement(); + _popup.Child = mediaElement; + + // It is legal (although not advisable) to provide a video file. By setting visibility to collapsed, only the sound track should play. + mediaElement.Visibility = Visibility.Collapsed; + + mediaElement.Source = MediaSource.CreateFromUri(sourceUri); + mediaElement.AutoPlay = true; + mediaElement.MediaPlayer.Volume = this.Volume; + mediaElement.MediaPlayer.MediaEnded += this.MediaElement_MediaEnded; + mediaElement.MediaPlayer.MediaFailed += this.MediaPlayer_MediaFailed; + + this._popup.IsOpen = true; + return true; + } + + private void MediaPlayer_MediaFailed(MediaPlayer sender, MediaPlayerFailedEventArgs args) + { + // TODO: We should probably have some system/properties to report/bubble errors here + ClosePopup(); + } + + private void MediaElement_MediaEnded(MediaPlayer sender, object args) + { + ClosePopup(); + } + + private void ClosePopup() + { + void closePopupImpl() + { + if (this._popup != null) { - closePopupImpl(); + this._popup.IsOpen = false; + this._popup.Child = null; + this._popup = null; } - else - { - // In WinUI3 the Media events are called on a background thread, so ensure we're on the UI thread to modify our popup container. - _queue.TryEnqueue(DispatcherQueuePriority.Normal, closePopupImpl); - } - } - } + } + + if (_queue.HasThreadAccess) + { + closePopupImpl(); + } + else + { + // In WinUI3 the Media events are called on a background thread, so ensure we're on the UI thread to modify our popup container. + _queue.TryEnqueue(DispatcherQueuePriority.Normal, closePopupImpl); + } + } } diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Trigger.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Trigger.cs index 5a08422..35dd72a 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Trigger.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Trigger.cs @@ -12,40 +12,39 @@ using Windows.UI.Xaml.Markup; #endif -namespace Microsoft.Xaml.Interactivity +namespace Microsoft.Xaml.Interactivity; + +/// +/// A base class for behaviors, implementing the basic plumbing of ITrigger +/// +[ContentPropertyAttribute(Name = "Actions")] +public abstract class Trigger : Behavior, ITrigger { /// - /// A base class for behaviors, implementing the basic plumbing of ITrigger + /// Identifies the dependency property. /// - [ContentPropertyAttribute(Name = "Actions")] - public abstract class Trigger : Behavior, ITrigger - { - /// - /// Identifies the dependency property. - /// - [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] - public static readonly DependencyProperty ActionsProperty = DependencyProperty.Register( - "Actions", - typeof(ActionCollection), - typeof(Trigger), - new PropertyMetadata(null)); + [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] + public static readonly DependencyProperty ActionsProperty = DependencyProperty.Register( + "Actions", + typeof(ActionCollection), + typeof(Trigger), + new PropertyMetadata(null)); - /// - /// Gets the collection of actions associated with the behavior. This is a dependency property. - /// - public ActionCollection Actions + /// + /// Gets the collection of actions associated with the behavior. This is a dependency property. + /// + public ActionCollection Actions + { + get { - get + ActionCollection actionCollection = (ActionCollection)this.GetValue(Trigger.ActionsProperty); + if (actionCollection == null) { - ActionCollection actionCollection = (ActionCollection)this.GetValue(Trigger.ActionsProperty); - if (actionCollection == null) - { - actionCollection = new ActionCollection(); - this.SetValue(Trigger.ActionsProperty, actionCollection); - } - - return actionCollection; + actionCollection = new ActionCollection(); + this.SetValue(Trigger.ActionsProperty, actionCollection); } + + return actionCollection; } } } diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/TriggerOfT.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/TriggerOfT.cs index 3a4a5fd..90c8ea7 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/TriggerOfT.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/TriggerOfT.cs @@ -10,40 +10,39 @@ using Windows.UI.Xaml; #endif -namespace Microsoft.Xaml.Interactivity +namespace Microsoft.Xaml.Interactivity; + +/// +/// A base class for behaviors, implementing the basic plumbing of ITrigger +/// +/// The object type to attach to +public abstract class Trigger : Trigger where T : DependencyObject { /// - /// A base class for behaviors, implementing the basic plumbing of ITrigger + /// Gets the object to which this behavior is attached. /// - /// The object type to attach to - public abstract class Trigger : Trigger where T : DependencyObject + [EditorBrowsable(EditorBrowsableState.Never)] + public new T AssociatedObject { - /// - /// Gets the object to which this behavior is attached. - /// - [EditorBrowsable(EditorBrowsableState.Never)] - public new T AssociatedObject - { - get { return base.AssociatedObject as T; } - } + get { return base.AssociatedObject as T; } + } - /// - /// Called after the behavior is attached to the . - /// - /// - /// Override this to hook up functionality to the - /// - protected override void OnAttached() - { - base.OnAttached(); + /// + /// Called after the behavior is attached to the . + /// + /// + /// Override this to hook up functionality to the + /// + protected override void OnAttached() + { + base.OnAttached(); - if (this.AssociatedObject == null) - { - string actualType = base.AssociatedObject.GetType().FullName; - string expectedType = typeof(T).FullName; - string message = string.Format(ResourceHelper.GetString("InvalidAssociatedObjectExceptionMessage"), actualType, expectedType); - throw new InvalidOperationException(message); - } + if (this.AssociatedObject == null) + { + string actualType = base.AssociatedObject.GetType().FullName; + string expectedType = typeof(T).FullName; + string message = string.Format(ResourceHelper.GetString("InvalidAssociatedObjectExceptionMessage"), actualType, expectedType); + throw new InvalidOperationException(message); } } } diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/TypeConstraintAttribute.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/TypeConstraintAttribute.cs index 06c8fb4..4fe6e15 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/TypeConstraintAttribute.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/TypeConstraintAttribute.cs @@ -3,30 +3,29 @@ using System; -namespace Microsoft.Xaml.Interactivity +namespace Microsoft.Xaml.Interactivity; + +/// +/// Specifies type constraints on the AssociatedObject of . +/// +[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] +public sealed class TypeConstraintAttribute : Attribute { /// - /// Specifies type constraints on the AssociatedObject of . + /// Initializes a new instance of the class. /// - [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] - public sealed class TypeConstraintAttribute : Attribute + /// The constraint type. + public TypeConstraintAttribute(Type constraint) { - /// - /// Initializes a new instance of the class. - /// - /// The constraint type. - public TypeConstraintAttribute(Type constraint) - { - this.Constraint = constraint; - } + this.Constraint = constraint; + } - /// - /// Gets the constraint type. - /// - public Type Constraint - { - get; - private set; - } + /// + /// Gets the constraint type. + /// + public Type Constraint + { + get; + private set; } } \ No newline at end of file diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Utility/IVisualTreeHelper.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Utility/IVisualTreeHelper.cs index 5560525..a07803f 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Utility/IVisualTreeHelper.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Utility/IVisualTreeHelper.cs @@ -7,26 +7,25 @@ using Windows.UI.Xaml; #endif -namespace Microsoft.Xaml.Interactivity.Utility +namespace Microsoft.Xaml.Interactivity.Utility; + +/// +/// Abstraction layer over the UWP's VisualTreeHelper class so we can +/// mock it for unit testing purposes where an actual view won't be available. +/// +internal interface IVisualTreeHelper { /// - /// Abstraction layer over the UWP's VisualTreeHelper class so we can - /// mock it for unit testing purposes where an actual view won't be available. + /// Returns an object's parent object in the visual tree. /// - internal interface IVisualTreeHelper - { - /// - /// Returns an object's parent object in the visual tree. - /// - /// - /// The object for which to get the parent object. - /// - /// - /// The parent object of the reference object in the visual tree. - /// - /// - /// THREAD SAFETY: This method should be called on the object's Dispatcher thread. - /// - DependencyObject GetParent(DependencyObject reference); - } + /// + /// The object for which to get the parent object. + /// + /// + /// The parent object of the reference object in the visual tree. + /// + /// + /// THREAD SAFETY: This method should be called on the object's Dispatcher thread. + /// + DependencyObject GetParent(DependencyObject reference); } diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Utility/UwpVisualTreeHelper.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Utility/UwpVisualTreeHelper.cs index 4688b84..624fd12 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Utility/UwpVisualTreeHelper.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/Utility/UwpVisualTreeHelper.cs @@ -9,20 +9,19 @@ using Windows.UI.Xaml.Media; #endif -namespace Microsoft.Xaml.Interactivity.Utility -{ - /// - /// IVisualTreeHelper implementation that calls the real VisualTreeHelper. - /// - internal class UwpVisualTreeHelper : IVisualTreeHelper - { - #region IVisualTreeHelper implementation +namespace Microsoft.Xaml.Interactivity.Utility; - public DependencyObject GetParent(DependencyObject reference) - { - return VisualTreeHelper.GetParent(reference); - } +/// +/// IVisualTreeHelper implementation that calls the real VisualTreeHelper. +/// +internal class UwpVisualTreeHelper : IVisualTreeHelper +{ + #region IVisualTreeHelper implementation - #endregion + public DependencyObject GetParent(DependencyObject reference) + { + return VisualTreeHelper.GetParent(reference); } + + #endregion } diff --git a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/VisualStateUtilities.cs b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/VisualStateUtilities.cs index 8e57283..c8d660f 100644 --- a/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/VisualStateUtilities.cs +++ b/src/BehaviorsSDKManaged/Microsoft.Xaml.Interactivity.Shared/VisualStateUtilities.cs @@ -15,137 +15,136 @@ using Windows.UI.Xaml.Media; #endif -namespace Microsoft.Xaml.Interactivity +namespace Microsoft.Xaml.Interactivity; + +/// +/// Provides various standard operations for working with . +/// +public static class VisualStateUtilities { /// - /// Provides various standard operations for working with . + /// Transitions the control between two states. /// - public static class VisualStateUtilities + /// The to transition between states. + /// The state to transition to. + /// True to use a to transition between states; otherwise, false. + /// True if the is successfully transitioned to the new state; otherwise, false. + /// or is null. + public static bool GoToState(Control control, string stateName, bool useTransitions) { - /// - /// Transitions the control between two states. - /// - /// The to transition between states. - /// The state to transition to. - /// True to use a to transition between states; otherwise, false. - /// True if the is successfully transitioned to the new state; otherwise, false. - /// or is null. - public static bool GoToState(Control control, string stateName, bool useTransitions) + if (control == null) { - if (control == null) - { - throw new ArgumentNullException(nameof(control)); - } - - if (string.IsNullOrEmpty(stateName)) - { - throw new ArgumentNullException(nameof(stateName)); - } + throw new ArgumentNullException(nameof(control)); + } - control.ApplyTemplate(); - return VisualStateManager.GoToState(control, stateName, useTransitions); + if (string.IsNullOrEmpty(stateName)) + { + throw new ArgumentNullException(nameof(stateName)); } - /// - /// Gets the value of the VisualStateManager.VisualStateGroups attached property. - /// - /// The from which to get the VisualStateManager.VisualStateGroups. - /// The list of VisualStateGroups in the given element. - /// is null. - public static IList GetVisualStateGroups(FrameworkElement element) + control.ApplyTemplate(); + return VisualStateManager.GoToState(control, stateName, useTransitions); + } + + /// + /// Gets the value of the VisualStateManager.VisualStateGroups attached property. + /// + /// The from which to get the VisualStateManager.VisualStateGroups. + /// The list of VisualStateGroups in the given element. + /// is null. + public static IList GetVisualStateGroups(FrameworkElement element) + { + if (element == null) { - if (element == null) - { - throw new ArgumentNullException(nameof(element)); - } + throw new ArgumentNullException(nameof(element)); + } - IList visualStateGroups = VisualStateManager.GetVisualStateGroups(element); + IList visualStateGroups = VisualStateManager.GetVisualStateGroups(element); - if (visualStateGroups == null || visualStateGroups.Count == 0) + if (visualStateGroups == null || visualStateGroups.Count == 0) + { + int childrenCount = VisualTreeHelper.GetChildrenCount(element); + if (childrenCount > 0) { - int childrenCount = VisualTreeHelper.GetChildrenCount(element); - if (childrenCount > 0) + FrameworkElement childElement = VisualTreeHelper.GetChild(element, 0) as FrameworkElement; + if (childElement != null) { - FrameworkElement childElement = VisualTreeHelper.GetChild(element, 0) as FrameworkElement; - if (childElement != null) - { - visualStateGroups = VisualStateManager.GetVisualStateGroups(childElement); - } + visualStateGroups = VisualStateManager.GetVisualStateGroups(childElement); } } + } - return visualStateGroups; + return visualStateGroups; + } + + /// + /// Find the nearest parent which contains visual states. + /// + /// The from which to find the nearest stateful control. + /// The nearest that contains visual states; else null. + /// is null. + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Stateful")] + public static Control FindNearestStatefulControl(FrameworkElement element) + { + if (element == null) + { + throw new ArgumentNullException(nameof(element)); } - /// - /// Find the nearest parent which contains visual states. - /// - /// The from which to find the nearest stateful control. - /// The nearest that contains visual states; else null. - /// is null. - [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Stateful")] - public static Control FindNearestStatefulControl(FrameworkElement element) + // Try to find an element which is the immediate child of a UserControl, ControlTemplate or other such "boundary" element + FrameworkElement parent = element.Parent as FrameworkElement; + + // bubble up looking for a place to stop + while (!VisualStateUtilities.HasVisualStateGroupsDefined(element) && VisualStateUtilities.ShouldContinueTreeWalk(parent)) { - if (element == null) - { - throw new ArgumentNullException(nameof(element)); - } + element = parent; + parent = parent.Parent as FrameworkElement; + } - // Try to find an element which is the immediate child of a UserControl, ControlTemplate or other such "boundary" element - FrameworkElement parent = element.Parent as FrameworkElement; + if (VisualStateUtilities.HasVisualStateGroupsDefined(element)) + { + // Once we've found such an element, use the VisualTreeHelper to get it's parent. For most elements the two are the + // same, but for children of a ControlElement this will give the control that contains the template. + Control templatedParent = VisualTreeHelper.GetParent(element) as Control; - // bubble up looking for a place to stop - while (!VisualStateUtilities.HasVisualStateGroupsDefined(element) && VisualStateUtilities.ShouldContinueTreeWalk(parent)) + if (templatedParent != null) { - element = parent; - parent = parent.Parent as FrameworkElement; + return templatedParent; } - - if (VisualStateUtilities.HasVisualStateGroupsDefined(element)) + else { - // Once we've found such an element, use the VisualTreeHelper to get it's parent. For most elements the two are the - // same, but for children of a ControlElement this will give the control that contains the template. - Control templatedParent = VisualTreeHelper.GetParent(element) as Control; - - if (templatedParent != null) - { - return templatedParent; - } - else - { - return element as Control; - } + return element as Control; } - - return null; } - private static bool HasVisualStateGroupsDefined(FrameworkElement element) + return null; + } + + private static bool HasVisualStateGroupsDefined(FrameworkElement element) + { + return element != null && VisualStateManager.GetVisualStateGroups(element).Count != 0; + } + + private static bool ShouldContinueTreeWalk(FrameworkElement element) + { + if (element == null) { - return element != null && VisualStateManager.GetVisualStateGroups(element).Count != 0; + return false; } - - private static bool ShouldContinueTreeWalk(FrameworkElement element) + else if (element is UserControl) { - if (element == null) - { - return false; - } - else if (element is UserControl) + return false; + } + else if (element.Parent == null) + { + // Stop if parent's parent is null AND parent isn't the template root of a ControlTemplate or DataTemplate. + FrameworkElement templatedParent = VisualTreeHelper.GetParent(element) as FrameworkElement; + if (templatedParent == null || (!(templatedParent is Control) && !(templatedParent is ContentPresenter))) { return false; } - else if (element.Parent == null) - { - // Stop if parent's parent is null AND parent isn't the template root of a ControlTemplate or DataTemplate. - FrameworkElement templatedParent = VisualTreeHelper.GetParent(element) as FrameworkElement; - if (templatedParent == null || (!(templatedParent is Control) && !(templatedParent is ContentPresenter))) - { - return false; - } - } - - return true; } + + return true; } }