View Issue Details

IDProjectCategoryView StatusLast Update
0002634NoesisGUIUnrealpublic2023-09-26 20:30
ReporterThisIsMyUserName Assigned Tosfernandez  
PrioritynormalSeverityminor 
Status resolvedResolutionfixed 
Product Version3.2.1 
Target Version3.2.2Fixed in Version3.2.2 
Summary0002634: StoryboardCompletedTrigger is invoked for all items in list
Description

When Storyboard is played for item in list, the StoryboardCompletedTrigger is invoked for all items in list.

Noesis Forum post - https://www.noesisengine.com/forums/viewtopic.php?t=2976

Steps To Reproduce

Using Noesis 3.2.1 and Unreal Engine

Create a DataTemplate that contains a Storyboard and StoryboardCompletedTrigger.

Create a list of DataTemplate items (at least 2 items)

Play the Storyboard on 1 item

Observe StoryboardCompletedTrigger function being called on every item in the list

PlatformAny

Relationships

related to 0002653 resolvedsfernandez ControlStoryboardAction inside ControlTemplates only works for one instance 
related to 0002052 resolvedsfernandez Storyboard Completed event triggered for all instances of a template 

Activities

sfernandez

sfernandez

2023-06-29 12:35

manager   ~0008572

Could you please try the attahed patch, it should fix your problem.

StoryboardCompletedTrigger.patch (8,694 bytes)   
Index: Include/NsApp/ControlStoryboardAction.h
===================================================================
--- Include/NsApp/ControlStoryboardAction.h	(revision 12571)
+++ Include/NsApp/ControlStoryboardAction.h	(working copy)
@@ -14,6 +14,12 @@
 #include <NsApp/StoryboardAction.h>
 
 
+namespace Noesis
+{
+class FrameworkElement;
+class Storyboard;
+}
+
 namespace NoesisApp
 {
 
@@ -68,6 +74,10 @@
     void SetControlStoryboardOption(ControlStoryboardOption option);
     //@}
 
+    /// Returns the element that is used as target to play the storyboard
+    static Noesis::FrameworkElement* FindStoryboardTarget(Noesis::Storyboard* storyboard,
+        Noesis::DependencyObject* associatedObject);
+
 public:
     static const Noesis::DependencyProperty* ControlStoryboardOptionProperty;
 
Index: Include/NsApp/StoryboardCompletedTrigger.h
===================================================================
--- Include/NsApp/StoryboardCompletedTrigger.h	(revision 12571)
+++ Include/NsApp/StoryboardCompletedTrigger.h	(working copy)
@@ -15,6 +15,7 @@
 
 namespace Noesis
 {
+class FrameworkElement;
 struct TimelineEventArgs;
 }
 
@@ -64,6 +65,7 @@
 
     /// From AttachableObject
     //@{
+    void OnAttached() override;
     void OnDetaching() override;
     //@}
 
@@ -75,6 +77,9 @@
 private:
     void OnStoryboardCompleted(Noesis::BaseComponent* sender, const Noesis::TimelineEventArgs& e);
 
+private:
+    Noesis::FrameworkElement* mTarget;
+
     NS_DECLARE_REFLECTION(StoryboardCompletedTrigger, StoryboardTrigger)
 };
 
Index: Src/ControlStoryboardAction.cpp
===================================================================
--- Src/ControlStoryboardAction.cpp	(revision 12571)
+++ Src/ControlStoryboardAction.cpp	(working copy)
@@ -9,6 +9,7 @@
 #include <NsGui/Storyboard.h>
 #include <NsGui/ResourceDictionary.h>
 #include <NsGui/FrameworkElement.h>
+#include <NsGui/FrameworkTemplate.h>
 #include <NsCore/ReflectionImplement.h>
 #include <NsCore/ReflectionImplementEnum.h>
 
@@ -60,6 +61,32 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
+Noesis::FrameworkElement* ControlStoryboardAction::FindStoryboardTarget(
+    Noesis::Storyboard* storyboard, Noesis::DependencyObject* associatedObject)
+{
+    Noesis::IUITreeNode* node = storyboard->GetNodeParent();
+
+    // For Storyboards defined in the Template Resources always use the associated object
+    Noesis::ResourceDictionary* resources = Noesis::DynamicCast<Noesis::ResourceDictionary*>(node);
+    if (resources != 0 &&
+        Noesis::DynamicCast<Noesis::FrameworkTemplate*>(resources->GetNodeParent()) != 0)
+    {
+        return Noesis::FindTreeElement(Noesis::DynamicCast<Noesis::IUITreeNode*>(associatedObject));
+    }
+
+    // Next try with the scope where Storyboard was defined
+    Noesis::FrameworkElement* target = Noesis::FindTreeElement(node);
+    if (target != 0 && target->IsConnectedToView())
+    {
+        return target;
+    }
+
+    // In case Storyboard was defined in Application resources or the Resources of a
+    // template element, we next try with the scope of the associated object
+    return Noesis::FindTreeElement(Noesis::DynamicCast<Noesis::IUITreeNode*>(associatedObject));
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
 void ControlStoryboardAction::Invoke(BaseComponent*)
 {
     Noesis::Storyboard* storyboard = GetStoryboard();
@@ -66,14 +93,7 @@
     DependencyObject* associatedObject = GetAssociatedObject();
     if (associatedObject != 0 && storyboard != 0)
     {
-        // First try with the scope where Storyboard was defined as target
-        Noesis::FrameworkElement* target = FindTreeElement(storyboard->GetNodeParent());
-        if (target == 0 || !target->IsConnectedToView())
-        {
-            // In case Storyboard was defined in Application resources or the Resources of a
-            // template element, we next try with the scope of the associated object as target
-            target = Noesis::FindTreeElement(Noesis::DynamicCast<IUITreeNode*>(associatedObject));
-        }
+        Noesis::FrameworkElement* target = FindStoryboardTarget(storyboard, associatedObject);
 
         // Execute the Storyboard action if we have a valid target connected to the UI tree
         if (target != 0 && target->IsConnectedToView())
@@ -83,7 +103,7 @@
                 case ControlStoryboardOption_Play:
                 {
                     Noesis::IUITreeNode* node = Noesis::DynamicCast<IUITreeNode*>(associatedObject);
-                    Noesis::FrameworkElement* ns = FindTreeElement(node);
+                    Noesis::FrameworkElement* ns = Noesis::FindTreeElement(node);
                     storyboard->Begin(target, ns, true);
                     break;
                 }
@@ -105,7 +125,7 @@
                     else
                     {
                         Noesis::IUITreeNode* node = Noesis::DynamicCast<IUITreeNode*>(associatedObject);
-                        Noesis::FrameworkElement* ns = FindTreeElement(node);
+                        Noesis::FrameworkElement* ns = Noesis::FindTreeElement(node);
                         storyboard->Begin(target, ns, true);
                     }
                     break;
Index: Src/StoryboardCompletedTrigger.cpp
===================================================================
--- Src/StoryboardCompletedTrigger.cpp	(revision 12571)
+++ Src/StoryboardCompletedTrigger.cpp	(working copy)
@@ -5,7 +5,9 @@
 
 
 #include <NsApp/StoryboardCompletedTrigger.h>
+#include <NsApp/ControlStoryboardAction.h>
 #include <NsGui/Storyboard.h>
+#include <NsGui/FrameworkElement.h>
 #include <NsGui/ResourceDictionary.h>
 #include <NsCore/ReflectionImplementEmpty.h>
 
@@ -14,7 +16,7 @@
 
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
-StoryboardCompletedTrigger::StoryboardCompletedTrigger()
+StoryboardCompletedTrigger::StoryboardCompletedTrigger(): mTarget(0)
 {
 }
 
@@ -57,6 +59,17 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
+void StoryboardCompletedTrigger::OnAttached()
+{
+    Noesis::Storyboard* storyboard = GetStoryboard();
+    if (storyboard != 0)
+    {
+        Noesis::DependencyObject* associatedObject = GetAssociatedObject();
+        mTarget = ControlStoryboardAction::FindStoryboardTarget(storyboard, associatedObject);
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
 void StoryboardCompletedTrigger::OnDetaching()
 {
     Noesis::Storyboard* storyboard = GetStoryboard();
@@ -64,11 +77,14 @@
     {
         storyboard->Completed() -= MakeDelegate(this,
             &StoryboardCompletedTrigger::OnStoryboardCompleted);
+
+        mTarget = 0;
     }
 }
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
-void StoryboardCompletedTrigger::OnStoryboardChanged(const Noesis::DependencyPropertyChangedEventArgs& e)
+void StoryboardCompletedTrigger::OnStoryboardChanged(
+    const Noesis::DependencyPropertyChangedEventArgs& e)
 {
     Noesis::Storyboard* oldStoryboard = e.OldValue<Noesis::Ptr<Noesis::Storyboard>>();
     Noesis::Storyboard* newStoryboard = e.NewValue<Noesis::Ptr<Noesis::Storyboard>>();
@@ -77,18 +93,27 @@
     {
         oldStoryboard->Completed() -= MakeDelegate(this,
             &StoryboardCompletedTrigger::OnStoryboardCompleted);
+
+        mTarget = 0;
     }
     if (newStoryboard != 0)
     {
         newStoryboard->Completed() += MakeDelegate(this,
             &StoryboardCompletedTrigger::OnStoryboardCompleted);
+
+        Noesis::DependencyObject* associatedObject = GetAssociatedObject();
+        mTarget = ControlStoryboardAction::FindStoryboardTarget(newStoryboard, associatedObject);
     }
 }
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
-void StoryboardCompletedTrigger::OnStoryboardCompleted(BaseComponent*, const Noesis::TimelineEventArgs&)
+void StoryboardCompletedTrigger::OnStoryboardCompleted(BaseComponent*,
+    const Noesis::TimelineEventArgs& e)
 {
-    InvokeActions(0);
+    if (e.target == mTarget)
+    {
+        InvokeActions(0);
+    }
 }
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////

Issue History

Date Modified Username Field Change
2023-06-28 12:43 ThisIsMyUserName New Issue
2023-06-28 12:43 ThisIsMyUserName Tag Attached: C++
2023-06-28 12:43 ThisIsMyUserName Tag Attached: Unreal
2023-06-28 12:48 sfernandez Assigned To => sfernandez
2023-06-28 12:48 sfernandez Status new => assigned
2023-06-28 12:48 sfernandez Product Version 3.2 => 3.2.1
2023-06-28 12:48 sfernandez Target Version => 3.2.2
2023-06-29 12:35 sfernandez Note Added: 0008572
2023-06-29 12:35 sfernandez File Added: StoryboardCompletedTrigger.patch
2023-06-29 12:35 sfernandez Status assigned => feedback
2023-07-24 13:00 sfernandez Relationship added related to 0002653
2023-07-24 13:01 sfernandez Relationship added related to 0002052
2023-09-26 20:30 sfernandez Status feedback => resolved
2023-09-26 20:30 sfernandez Resolution open => fixed
2023-09-26 20:30 sfernandez Fixed in Version => 3.2.2