locked
TriggerAction's properties not bound when used with Loaded EventTrigger in a dialog RRS feed

  • Question

  • Hi there,

    I originally posted this question on the WPF forums but was told it might be a good idea to post it here. For a full description, please see the original post.

    The summary is that, when the Interactivity.EventTrigger with the "Loaded" event of the content element of a window (dialog in my case), the TriggerAction<T> is invoked before binding has completed (even when DataContext is assigned in the constructor of the view)

    This is a difficult scenar to repro without the ability to attach code archives, as you can imagine. Regardless, I've managed to do it in as little classes as I could (and without a Prism dependency):

    1. Create a new WPF application called "DialogBindingRepro"

    2. Add a reference to Microsoft.Expression.Interactions and System.Windows.Interactivity

    3. Add a class named InvokeCommandAction and paste the code from below

    4. Replace the content of the other files iowith the code below

    5. Run the application in debug

    6. Click the button in the main window

    Expected (in output):

    Command accessible from LoadedEvent
    
    Command accessible from TriggerAction

    Actual (in output):

    Command accessible from LoadedEvent

    That is, InvokeCommandAction.Invoke is being called, but it is being called before binding has completed (InvokeCommandAction.Command is still null).

    Below is the code for the various files:

    MainWindow.xaml

    <Window x:Class="DialogBindingRepro.MainWindow"
    
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    
      Title="MainWindow" Height="350" Width="525">
    
     <Grid>
    
      <Button Click="Button_Click" Content="Show Dialog" />
    
     </Grid>
    
    </Window>
    
    

    MainWindow.xaml.cs

    private void Button_Click(object sender, RoutedEventArgs e)
    
    {
    
     var contentDialog = new Window { Content = new DialogContent() };
    
     contentDialog.Owner = this;
    
     contentDialog.SizeToContent = SizeToContent.WidthAndHeight;
    
     contentDialog.ShowDialog();
    
    }
    
    

    DialogContent.xaml

    <UserControl x:Class="DialogBindingRepro.DialogContent"
    
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    
        xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" 
    
        xmlns:a="clr-namespace:DialogBindingRepro"
    
        mc:Ignorable="d" 
    
        d:DesignHeight="300" d:DesignWidth="300">
    
    
    
     <i:Interaction.Triggers>
    
      <i:EventTrigger EventName="Loaded">
    
       <a:InvokeCommandAction Command="{Binding LoadedCommand}" />
    
      </i:EventTrigger>
    
     </i:Interaction.Triggers>
    
    
    
     <Grid>
    
      
    
     </Grid>
    
    </UserControl>
    
    

    DialogContent.xaml.cs

    public partial class DialogContent : UserControl
    
    {
    
     public DialogContent()
    
     {
    
      this.Loaded += new RoutedEventHandler(DialogContent_Loaded);
    
      this.DataContext = new { LoadedComment = new TestCommand() };
    
    
    
      InitializeComponent();
    
     }
    
    
    
     void DialogContent_Loaded(object sender, RoutedEventArgs e)
    
     {
    
      if (((ViewModel)DataContext).LoadedCommand != null)
    
      {
    
       Trace.WriteLine("Command accessible from LoadedEvent");
    
      }
    
     }
    
    
    
     private class TestCommand : ICommand
    
     {
    
      public bool CanExecute(object parameter)
    
      {
    
       return true;
    
      }
    
    
    
      public event EventHandler CanExecuteChanged;
    
    
    
      public void Execute(object parameter)
    
      {
    
       Trace.WriteLine("Command accessible from TriggerAction");
    
      }
    
     }
    
    
    
     private class ViewModel
    
     {
    
      public ICommand LoadedCommand { get; set; }
    
     }
    
    }
    
    

    InvokeCommandAction.cs

    public sealed class InvokeCommandAction : TriggerAction<DependencyObject>
    
    {
    
     public static readonly DependencyProperty CommandProperty = DependencyProperty
    
      .Register("Command", typeof(ICommand), typeof(InvokeCommandAction));
    
    
    
     public static readonly DependencyProperty CommandParameterProperty = DependencyProperty
    
      .Register("CommandParameter", typeof(object), typeof(InvokeCommandAction));
    
    
    
     protected override void Invoke(object parameter)
    
     {
    
      if (Command != null && Command.CanExecute(CommandParameter))
    
      {
    
       Command.Execute(CommandParameter);
    
      }
    
     }
    
    
    
     public ICommand Command
    
     {
    
      get { return GetValue(CommandProperty) as ICommand; }
    
      set { SetValue(CommandProperty, value); }
    
     }
    
    
    
     public object CommandParameter
    
     {
    
      get { return GetValue(CommandParameterProperty); }
    
      set { SetValue(CommandParameterProperty, value); }
    
     }
    
    }
    
    

     

    Tuesday, November 16, 2010 1:45 PM

All replies

  • On an unrelated note, the code formatting on this site is infuriating. I'd recommend using something similar to Stack Oveflow.
    Tuesday, November 16, 2010 1:53 PM