2

How can I bind a UserControl's FrameworkElement event to a view model command? I use MVVM and Prism so clear separation between the view the view-model would be nice.

I'd tried multiple things, and none of them worked:

<i:Interaction.Triggers>
    <i:EventTrigger EventName="FrameworkElement.Unloaded">
        <i:InvokeCommandAction Command="{Binding Unloaded}" />
    </i:EventTrigger>
</i:Interaction.Triggers>

also using this tutorial http://blog.functionalfun.net/2008/09/hooking-up-commands-to-events-in-wpf.html

local:FrameworkElementBehavior.UnloadedCommand="{Binding Unloaded}"

Do I have no choice but to add some functions to my code-behind?

Neither of the attempts above error out, but the command does not execute.

Here's my view model:

public class CustomerViewModel : PosViewModelBase
{
    public ICommand Unloaded
    {
        get { return new UnloadedCommand(); }
    }

    public CustomerViewModel()
    {

    }

    private class UnloadedCommand : ICommand
    {
        public bool CanExecute(object parameter)
        {
            return true;
        }

        public event EventHandler CanExecuteChanged;

        public void Execute(object parameter)
        {
            Debug.WriteLine("Customer stuff is out of view");
        }
    }
}
Dave Clemmer
  • 3,741
  • 12
  • 49
  • 72
Chris Klepeis
  • 9,783
  • 16
  • 83
  • 149
  • Did you check the output window in VS for binding errors? – Thomas Levesque Jun 07 '12 at 14:44
  • In addition, the event is definitely firing. When I change the name of the command property something invalid in the binding, I do indeed get output window errors. So the binding appears to happen, the commmand just doesn't execute. – Chris Klepeis Jun 07 '12 at 14:52

1 Answers1

2

I think the problem could be in Unloaded event.

From MSDN page http://msdn.microsoft.com/en-us/library/ms754221.aspx#common_events:

Unloaded is raised last and is initiated by either the presentation source or the visual parent being removed. When Unloaded is raised and handled, the element that is the event source parent (as determined by Parent property) or any given element upwards in the logical or visual trees may have already been unset, meaning that data binding, resource references, and styles may not be set to their normal or last known run-time value.

Stipo
  • 4,566
  • 1
  • 21
  • 37
  • So what would be the best way to raise my command when the UserControl is not visible on the screen? Code-behind or perhaps the VisibilityChanged event? – Chris Klepeis Jun 07 '12 at 20:00
  • Changing visibility doesn't mean that Control is actually detached from the visual tree, it could still be there, just hidden. I assume that you want to execute a command when a view is detached from the visual tree. I am not sure if this will work in all the scenarios, but you could use DataContextChanged event and in its code-behind handler check if ((FrameworkElement)sender).Parent == null and then retrieve view-model through e.OldValue and execute its command. – Stipo Jun 07 '12 at 21:08
  • Yeah, I just need to figure out a way to execute a command (passing the UiElement to the command) when the content of my ContentControl changes. I basically want to take a snapshot of the control for navigation purposes so the user can select it to go back to it. – Chris Klepeis Jun 07 '12 at 21:10
  • I think I found a solution: http://stackoverflow.com/questions/2599788/wpf-data-binding-trigger-before-content-changed basically creating a ContentChangingEvent on a class that inherits ContentControl. Gunna try it out. – Chris Klepeis Jun 07 '12 at 21:17
  • Still no dice. I'd have to use UI elements in my view model. No idea how to get a screenshot to my viewmodel without breaking MVVM. – Chris Klepeis Jun 07 '12 at 22:40
  • I suggest you start another question regarding this issue and provide more info about it. – Stipo Jun 08 '12 at 14:57
  • Well, as you said, you shouldn't be passing UIElement to viewmodel because it breaks MVVM. Your view should be stateless and all information about its state should originate from its viewmodel. If you have ContentControl.Content property data-bound to some viewmodel property, then you should handle changing the ContentControl.Content in a setter of a viewmodel property to which ContentControl.Content is bound to and save its previous value so you can set it back, if user asks this. – Stipo Jun 08 '12 at 15:17