wpftemplatesdata-bindinginteractioncommandparameter

TemplateBinding as InvokeCommandAction CommandParameter not working?


I'm trying to write a reusable template for a control I want to use several times in my window. In it I have some commands with CommandParameter. The CommandParameter is an object I want to pass via the "Tag" property of this template.

For the "MenuItem" CommandParameter and the StackPanel "DataContext" this is working just fine. But for the "MouseDown" event (or "PreviewMouseDown", I tried both) via InvokeCommandAction I'm only getting a null as parameter. It is firing the command and calls the right method, but the parameter is always null.

Here my Xaml (shortend):

<Window.Resources>
        <ControlTemplate x:Key="FavControl" TargetType="ContentControl">
            <StackPanel>
                <StackPanel.ContextMenu>
                    <ContextMenu IsEnabled="{Binding FavContextMenuEnabled}">
                        <MenuItem Header="Bearbeiten"
                                  Command="{Binding FavContextMenuEditCmd}"
                                  CommandParameter="{TemplateBinding Tag}" />
                        <MenuItem Header="Löschen"
                                  Command="{Binding FavContextMenuDeleteCmd}"
                                  CommandParameter="{TemplateBinding Tag}" />
                        <Separator IsEnabled="{Binding UserisDev}" />
                        <MenuItem Header="Entwicklung"
                                  Command="{Binding FavContextMenuStartDevCmd}"
                                  CommandParameter="{TemplateBinding Tag}"
                                  IsEnabled="{Binding UserisDev}" />
                        <MenuItem Header="Starte Objekt"
                                  Command="{Binding FavContextMenuRunObjectCmd}"
                                  CommandParameter="{TemplateBinding Tag}"
                                  IsEnabled="{Binding UserisDev}" />
                    </ContextMenu>
                </StackPanel.ContextMenu>
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="MouseDown">
                        <i:InvokeCommandAction Command="{Binding FavoriteClickCmd}" CommandParameter="{TemplateBinding Tag}" />
                    </i:EventTrigger>
                </i:Interaction.Triggers>
                <StackPanel Orientation="Vertical" DataContext="{TemplateBinding Tag}">
                    <Image Source="{Binding FavImage, UpdateSourceTrigger=PropertyChanged,Mode=OneWay}" 
                           HorizontalAlignment="Center" VerticalAlignment="Center" Height="70" Width="70" />
                    <TextBlock Text="{Binding Description}" HorizontalAlignment="Center" />
                </StackPanel>
            </StackPanel>
        </ControlTemplate>
    </Window.Resources>

<!-- ... -->

<ContentControl Grid.Row="0" Grid.Column="0" Template="{StaticResource FavControl}" Tag="{Binding FavoriteArray[0]}" />
<ContentControl Grid.Row="0" Grid.Column="1" Template="{StaticResource FavControl}" Tag="{Binding FavoriteArray[1]}" />
<ContentControl Grid.Row="0" Grid.Column="2" Template="{StaticResource FavControl}" Tag="{Binding FavoriteArray[2]}" />

<!-- ... -->

I need this parameter in the code behind method to know which object to work with. So, how can I pass this object? Why is the TemplateBinding not working? Can anybody tell me, what I'm doing wrong?

P.S.: Sorry for errors, english is not my native language :)


Solution

  • Instead of TemplateBinding, use a RelativeSource binding to TemplatedParent.

    <b:InvokeCommandAction Command="{Binding FavoriteClickCmd}"
                           CommandParameter="{Binding Tag, RelativeSource={RelativeSource TemplatedParent}}" />