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

  • Question

  • I have a view that is being used as the Content property in a Window shown with ShowDialog (though Show produces the same problem)

    The view accepts its view model in its constructor and assigns it to its DataContext

    I am using Blend's interaction EventTrigger on the Loaded event to call a custom TriggerAction that has a Command dependency property bound to an ICommand property of the view model mentioned above.

    The problem is that, while the action's Invoke method is called, the Command property hasn't been bound and so the property is null.

    However, if I setup a custom event handler for Loaded, I can access the DataContext and the source of the bound command is not null and I can call it successfully. The problem only occurs when going via the event trigger.

    In addition, if I add the view to a region within an existing view the action is called and the command is bound correctly, so it seems restricted to views that are the root content of a window.

    NOTE: I'm using Prism but I don't think that's related to the problem

     

    • Moved by Yves.Z Thursday, November 18, 2010 8:57 AM Expression topic (From:Windows Presentation Foundation (WPF))
    Wednesday, November 10, 2010 9:08 AM

All replies

  • Hi Richard Szalay,

    Based on the information you supplied, we can not repro your problem. Could you kindly elaborate your issue? It would be appreciated if you could offer a simple ready-to-run demo thus you may get a better answer from other community members.

    By the way, since the problem you encounter is involved with Blend, you should post it in Expression Blend Forum. http://social.expression.microsoft.com/Forums/en-US/blend/threads

    Thank you!

     

    Best regards,

    Yves


    Please remember to click “Mark as Answer” on the post that helps you, and to click “Unmark as Answer” if a marked post does not actually answer your question. This can be beneficial to other community members reading the thread.
    Monday, November 15, 2010 2:57 AM
  • Hi Yves,

    This is a difficult scenario 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 with 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); }
     }
    }
    

     

    • Edited by Richard Szalay Tuesday, November 16, 2010 1:49 PM MainWindow.xaml.cs formatting
    Tuesday, November 16, 2010 1:45 PM