Question

I have a Button in a DataTemplate that is bound to a Command in my ViewModel. The button also has an EventTrigger that kicks off a Storyboard that hides the edit controls (of which the button is a part.)

The Storyboard works fine if I pick up the PreviewMouseDown event, but the Command never gets called. If I pick up the MouseDown event in my EventTrigger, the Command works, but the Storyboard doesn't execute.

How can I get both the Command and the Storyboard to execute when the button is clicked?

<Button Content="Save" Command="{Binding SaveCommand}" >
    <Button.Triggers>
        <EventTrigger RoutedEvent="Button.PreviewMouseDown">
            <EventTrigger.Actions>
                <BeginStoryboard Storyboard="{DynamicResource sbCloseTitleEdit}"/>
            </EventTrigger.Actions>
        </EventTrigger>
    </Button.Triggers>
</Button>
Was it helpful?

Solution

I ended up inelegantly solving my problem by adding a code-behind file for my ResourceDictionary that contains the DataTemplate. I wasn't aware that this was possible, but found this explanation:

Is it possible to set code behind a resource dictionary in WPF for event handling?

Instead of using the EventTrigger to begin a Storyboard that hides the edit controls I added a Click handler to the code-behind. It's a bit kludgy as I have to locate the panels relative to the button clicked as that is the only reference available, but it works.

Still looking for a better solution if anyone has one.

OTHER TIPS

Ive tried your code, and I find that it works OK with the event trigger on PreviewMouseDown, its just that the command is executed first, then the animation fires.

Heres my resources

<Storyboard x:Key="sbCloseTitleEdit">
  <ColorAnimation Storyboard.TargetProperty="(Rectangle.Fill).Color" 
                  To="Blue" Duration="0:0:3" Storyboard.TargetName="rect" >
  </ColorAnimation>
</Storyboard>

my xaml

<Grid>
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="Auto" />
    <ColumnDefinition Width="Auto" />
  </Grid.ColumnDefinitions>
  <Grid.RowDefinitions>
    <RowDefinition Height="Auto" />
  </Grid.RowDefinitions>
  <Button Content="Save" Command="{Binding SaveCommand}" >
    <Button.Triggers>
      <EventTrigger RoutedEvent="Button.PreviewMouseDown">
        <EventTrigger.Actions>
          <BeginStoryboard 
            Storyboard="{StaticResource sbCloseTitleEdit}"/>
        </EventTrigger.Actions>
      </EventTrigger>
    </Button.Triggers>
  </Button>
  <Rectangle Name="rect" Width="30" Height="30" 
             Grid.Column="1" Fill="Red" />
</Grid>

and my view model

public class MainViewModel
{
    public ActionCommand SaveCommand { get; private set; }
    public MainViewModel()
    {
        SaveCommand = new ActionCommand();
    }
}

public class ActionCommand : ICommand
{
    public void Execute(object parameter)
    {
        // gets fired if event trigger is preview mode
    }

    public bool CanExecute(object parameter)
    {
        return true;
    }

    public event EventHandler CanExecuteChanged;
}

are you sure you havent missed something ?

I achieved this by invoking the command within the eventtrigger along with the other action you want to trigger:

<Button Command="{Binding AcceptCommand}" Content="Accept">
  <i:Interaction.Triggers>
    <i:EventTrigger EventName="Click">
      <i:InvokeCommandAction Command="{Binding AcceptCommand}"/>
      <triggers:UpdatePropertyAction TargetObject="{Binding RelativeSource={RelativeSource AncestorType={x:Type Controls:ChildWindow}, Mode=FindAncestor}}" TargetProperty="DialogResult" Value="True"  />
    </i:EventTrigger>
  </i:Interaction.Triggers>
</Button>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top