- BigAnt-JustenG
- Posts: 1
- Joined:
i:Interaction.Triggers on Templates and Custom Controls are not instanced
Currently trying to implement a Custom Control or Style that will act as a standard template for most of our views.
This standard view contains the following triggers;
This Style contains the required Intro and Outro storyboards.
In the regular occurrences that there is more than one object using this style at the same time, when the StoryboardCompletedTrigger is fired, it is fired on all instances at the same time.
This then calls the InvokeCommandAction on the OnOutroComplete callback on all instances that are using this style, even though they were not specifically playing the Outro animation.
Is there a way to create an instance of this resource so that these trigger only function per instance?
Rather than a static global instance being used for all objects using this style.
Alternatively, is there another way to implement a standard set of Triggers across a collection of views without needing to have the same code written out a numerous amount of times?
Another thought I had;
Looking through the Custom Controls documentation I found the use of ResourceKeyType and Overriding the DefaultStyleKey property.
Here -> https://www.noesisengine.com/docs/Gui.C ... trols.html
Is the ResourceKeyType::Create(type) function creating an instance of this resource? If so this might be what I'm looking for.
However, it seems that this ResourceKeyType has been removed from Noesis 3.0
This standard view contains the following triggers;
Code: Select all
<ControlTemplate>
<Grid>
<Grid.Resources>
... Intro and Outro anims
</Grid.Resources>
<ContentPresenter/>
<i:Interaction.Triggers>
<ei:DataTrigger Binding="{Binding m_playIntro, Mode=OneWay}" Value="True">
<ei:ControlStoryboardAction Storyboard="{StaticResource Intro}" ControlStoryboardOption="Play" />
</ei:DataTrigger>
<ei:StoryboardCompletedTrigger Storyboard="{StaticResource Intro}">
<noesis:SetFocusAction TargetName="RootGrid"/>
</ei:StoryboardCompletedTrigger>
<ei:DataTrigger Binding="{Binding m_playOutro, Mode=OneWay}" Value="True">
<ei:ControlStoryboardAction Storyboard="{StaticResource Outro}" ControlStoryboardOption="Play" />
</ei:DataTrigger>
<ei:StoryboardCompletedTrigger Storyboard="{StaticResource Outro}">
<i:InvokeCommandAction Command="{Binding OnOutroComplete}" />
</ei:StoryboardCompletedTrigger>
</i:Interaction.Triggers>
</Grid>
</ControlTemplate>
In the regular occurrences that there is more than one object using this style at the same time, when the StoryboardCompletedTrigger is fired, it is fired on all instances at the same time.
This then calls the InvokeCommandAction on the OnOutroComplete callback on all instances that are using this style, even though they were not specifically playing the Outro animation.
Is there a way to create an instance of this resource so that these trigger only function per instance?
Rather than a static global instance being used for all objects using this style.
Alternatively, is there another way to implement a standard set of Triggers across a collection of views without needing to have the same code written out a numerous amount of times?
Another thought I had;
Looking through the Custom Controls documentation I found the use of ResourceKeyType and Overriding the DefaultStyleKey property.
Here -> https://www.noesisengine.com/docs/Gui.C ... trols.html
Is the ResourceKeyType::Create(type) function creating an instance of this resource? If so this might be what I'm looking for.
However, it seems that this ResourceKeyType has been removed from Noesis 3.0
-
sfernandez
Site Admin
- Posts: 2991
- Joined:
Re: i:Interaction.Triggers on Templates and Custom Controls are not instanced
Hi Justen,
The correct way of doing this in WPF is by defining the Storyboards as part of the resources of an element of the template VisualTree:
Unfortunately there is a known issue in Noesis template instantiation that causes the problem you are seeing, that all instances of the template share the same Storyboard and trigger the Completed event for all controls. Could you please report it to keep track of this issue?
In the meantime there is a workaround you can use:
The way you should override the DefaultStyleKey property is like this:
Anyway, adding this to your control won't fix the problem you described. That property is only used to specify the type that should be looked when getting the default Style.
The correct way of doing this in WPF is by defining the Storyboards as part of the resources of an element of the template VisualTree:
Code: Select all
<Grid
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions">
<Grid.Resources>
<ControlTemplate x:Key="t" TargetType="Control">
<Border x:Name="root" Background="Red">
<Border.Resources>
<Storyboard x:Key="intro">
<ColorAnimation To="Blue" Duration="0:0:0.5" Storyboard.TargetName="root" Storyboard.TargetProperty="Background.Color"/>
</Storyboard>
<Storyboard x:Key="outro">
<ColorAnimation To="Red" Duration="0:0:0.5" Storyboard.TargetName="root" Storyboard.TargetProperty="Background.Color"/>
</Storyboard>
</Border.Resources>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseEnter">
<ei:ControlStoryboardAction Storyboard="{StaticResource intro}"/>
</i:EventTrigger>
<i:EventTrigger EventName="MouseLeave">
<ei:ControlStoryboardAction Storyboard="{StaticResource outro}"/>
</i:EventTrigger>
<ei:StoryboardCompletedTrigger Storyboard="{StaticResource intro}">
<ei:ChangePropertyAction TargetName="root" PropertyName="Width" Value="150"/>
</ei:StoryboardCompletedTrigger>
<ei:StoryboardCompletedTrigger Storyboard="{StaticResource outro}">
<ei:ChangePropertyAction TargetName="root" PropertyName="Width" Value="200"/>
</ei:StoryboardCompletedTrigger>
</i:Interaction.Triggers>
</Border>
</ControlTemplate>
</Grid.Resources>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<Control Width="200" Height="100" Margin="0,10" Template="{StaticResource t}"/>
<Control Width="200" Height="100" Margin="0,10" Template="{StaticResource t}"/>
</StackPanel>
</Grid>
In the meantime there is a workaround you can use:
Code: Select all
<Grid
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions">
<Grid.Resources>
<ControlTemplate x:Key="t" TargetType="Control">
<Border x:Name="root" Background="Red">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseEnter">
<ei:ControlStoryboardAction>
<ei:ControlStoryboardAction.Storyboard>
<Storyboard>
<ColorAnimation To="Blue" Duration="0:0:0.5" Storyboard.TargetName="root" Storyboard.TargetProperty="Background.Color"/>
</Storyboard>
</ei:ControlStoryboardAction.Storyboard>
</ei:ControlStoryboardAction>
</i:EventTrigger>
<i:EventTrigger EventName="MouseLeave">
<ei:ControlStoryboardAction>
<ei:ControlStoryboardAction.Storyboard>
<Storyboard>
<ColorAnimation To="Red" Duration="0:0:0.5" Storyboard.TargetName="root" Storyboard.TargetProperty="Background.Color"/>
</Storyboard>
</ei:ControlStoryboardAction.Storyboard>
</ei:ControlStoryboardAction>
</i:EventTrigger>
<ei:StoryboardCompletedTrigger Storyboard="{Binding (i:Interaction.Triggers)[0].Actions[0].Storyboard, ElementName=root}">
<ei:ChangePropertyAction TargetName="root" PropertyName="Width" Value="150"/>
</ei:StoryboardCompletedTrigger>
<ei:StoryboardCompletedTrigger Storyboard="{Binding (i:Interaction.Triggers)[1].Actions[0].Storyboard, ElementName=root}">
<ei:ChangePropertyAction TargetName="root" PropertyName="Width" Value="200"/>
</ei:StoryboardCompletedTrigger>
</i:Interaction.Triggers>
</Border>
</ControlTemplate>
</Grid.Resources>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<Control Width="200" Height="100" Margin="0,10" Template="{StaticResource t}"/>
<Control Width="200" Height="100" Margin="0,10" Template="{StaticResource t}"/>
</StackPanel>
</Grid>
That documentation is not correctly updated to the latest version, thanks for pointing it out. We are going to review and update it for the next release.Another thought I had;
Looking through the Custom Controls documentation I found the use of ResourceKeyType and Overriding the DefaultStyleKey property.
Here -> https://www.noesisengine.com/docs/Gui.C ... trols.html
Is the ResourceKeyType::Create(type) function creating an instance of this resource? If so this might be what I'm looking for.
However, it seems that this ResourceKeyType has been removed from Noesis 3.0
The way you should override the DefaultStyleKey property is like this:
Code: Select all
data->OverrideMetadata<const Type*>(FrameworkElement::DefaultStyleKeyProperty,
"DefaultStyleKey", PropertyMetadata::Create<const Type*>(TypeOf<MyCustomControl>()));
Re: i:Interaction.Triggers on Templates and Custom Controls are not instanced
Hey Sergio, I've just encountered the bug where the storyboard is triggered for each DataTemplate instance inside an ItemsControl. I resolved it by using a TimerTrigger instead with the time set to the same length as the storyboard.
Did this bug ever get reported on the bugtracker? I just had a quick look and couldn't see it.
Cheers,
-Steven
Did this bug ever get reported on the bugtracker? I just had a quick look and couldn't see it.
Cheers,
-Steven
-
sfernandez
Site Admin
- Posts: 2991
- Joined:
Re: i:Interaction.Triggers on Templates and Custom Controls are not instanced
I created the ticket #2052 to keep track of this issue, thanks a lot for the reminder.
Who is online
Users browsing this forum: Ahrefs [Bot], Bing [Bot], Google [Bot] and 47 guests