EventTriggers inside ControlTemplates - avoiding leaks
Posted: 05 May 2022, 23:53
Hi guys,
So I'm attempting to fix the last remaining leaks in our game and I can't find a nice solution to the following problem.
So currently I'm using the NsApp EventTrigger inside a ControlTemplate to invoke a custom command action when a bespoke routed event is raised:
The issue is that SourceObject takes a ref counted pointer to the templated parent so it creates a cyclic reference which prevents the custom control from being cleaned up. I've managed to fix this in most other cases by using the NsGui.TriggerAction instead, i.e:
This fixes the bugs and allows me to replace NsApp.EventTrigger so long as the only action I do is BeginStoryboard, StopStoryboard or ControlStoryboard (as those are the only implemented actions which derive from NsGui.TriggerAction).
Is there a replacement for InvokeCommandAction? How would you suggest I go about doing this? Is there any other way for me to reference an event on the control template's templated parent without causing a cyclic dependency? A relative source binding or template binding do not work.
Cheers,
-Steven
So I'm attempting to fix the last remaining leaks in our game and I can't find a nice solution to the following problem.
So currently I'm using the NsApp EventTrigger inside a ControlTemplate to invoke a custom command action when a bespoke routed event is raised:
Code: Select all
<ControlTemplate x:Key="CustomControl.Template" TargetType="{x:Type Namespace:CustomControl}">
<Grid x:Name="Root"
Background="{TemplateBinding Background}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="CustomEvent" SourceObject="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}}">
<i:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Namespace:CustomControl}}, Path=(Namespace:CustomControl.CustomAction)}" />
</i:EventTrigger>
<i:EventTrigger EventName="CustomEvent2" SourceObject="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}}">
<i:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Namespace:CustomControl}}, Path=(Namespace:CustomControl.CustomAction2)}" CommandParameter="{Binding}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Grid>
</ControlTemplate>Code: Select all
<ControlTemplate x:Key="CustomControl.Template" TargetType="{x:Type Namespace:CustomControl}">
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="Namespace:CustomControl.CustomEvent">
<BeginStoryboard x:Name="CustomEventStoryboard" Storyboard="{StaticResource Storyboard}" />
</EventTrigger>
<EventTrigger RoutedEvent="Namespace:CustomControl.CustomEvent2">
<BeginStoryboard x:Name="CustomEvent2Storyboard" Storyboard="{StaticResource Storyboard}" />
</EventTrigger>
</ControlTemplate.Triggers>
<Grid x:Name="Root"
Background="{TemplateBinding Background}" >
</Grid>
</ControlTemplate>Is there a replacement for InvokeCommandAction? How would you suggest I go about doing this? Is there any other way for me to reference an event on the control template's templated parent without causing a cyclic dependency? A relative source binding or template binding do not work.
Cheers,
-Steven