91

So I've been searching around and cannot find out exactly how to do this. I'm creating a user control using MVVM and would like to run a command on the 'Loaded' event. I realize this requires a little bit of code behind, but I can't quite figure out what's needed. The command is located in the ViewModel, which is set as the datacontext of the view, but I'm not sure exactly how to route this so I can call it from the code behind of the loaded event. Basically what I want is something like this...

private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
    //Call command from viewmodel
}

Looking around I can't seem to find the syntax for this anywhere. Do I need to bind the command in the xaml first to be able to reference it? I notice the command bindings option within a user control will not let you bind commands as you can within something like a button...

<UserControl.CommandBindings>
    <CommandBinding Command="{Binding MyCommand}" /> <!-- Throws compile error -->
</UserControl.CommandBindings>

I'm sure there's a simple way to do this, but I can't for the life of me figure it out.

H.B.
  • 166,899
  • 29
  • 327
  • 400
Kevin DiTraglia
  • 25,746
  • 19
  • 92
  • 138

6 Answers6

171

Well, if the DataContext is already set you could cast it and call the command:

var viewModel = (MyViewModel)DataContext;
if (viewModel.MyCommand.CanExecute(null))
    viewModel.MyCommand.Execute(null);

(Change parameter as needed)

Alain
  • 26,663
  • 20
  • 114
  • 184
H.B.
  • 166,899
  • 29
  • 327
  • 400
  • 1
    Yeah that's exactly what I needed, I knew there was an easy way. Thanks! – Kevin DiTraglia Apr 12 '12 at 15:53
  • You should be checking if viewModel is null before trying to access MyCommand. I know my solution doesn't, but yours it the accepted answer so it should probably be in there. – Alain Apr 12 '12 at 15:57
  • 2
    @Alain: There's a note in my preface, i think people can introduce a check if in their case that is not guaranteed. – H.B. Apr 12 '12 at 15:58
  • When `MyCommand` in the ViewModel is defined with a certain `MyMethod`, why then would you not just execute `viewModel.MyMethod()`? Apart from the `CanExecute` which of course can be also called directly. – Gerard Feb 18 '14 at 22:55
  • @Gerard: If the class interface allows direct access to the method and the method does the same thing as the command you could do that. You should probably keep in mind however that the command may be semantically different from the method and that your code no longer is a representation of "calling the command in code" as changes to command's implementation will not be reflected anymore. – H.B. Feb 18 '14 at 23:08
  • @H.B. In what way would a command implementation (semantically ) differ from a method implementation? Or in combination with `CanExecute` two method implementations? – Gerard Feb 19 '14 at 11:44
  • @Gerard: That depends entirely on your code, if you for example have a `MarkAsReadCommand` and `MarkAsRead`/`CanMarkAsRead` methods, it's fairly safe to assume that there will never be any semantic difference. A counterexample would be something like a `SelectMessageCommand` and `DisplayMessage`/`CanDisplayMessage` methods, at first the command may only call the method but then other logic is added to the command like marking said message as read, which is not part of `DisplayMessage` method. – H.B. Feb 19 '14 at 15:36
  • @H.B. How does one "add logic to a command" other then altering the method logic? What am I missing about `ICommand`? – Gerard Feb 19 '14 at 20:26
  • @Gerard: `Execute` can contain any kind of implementation (and implementations may very well change during development), it is not bound to call a single method like `DisplayMessage`, that is where the difference between using the command interface (calling `Execute` in code) and directly calling the method (used in the `Execute` implementation) lies. – H.B. Feb 19 '14 at 20:52
  • @H.B. Changing the implementation of `Execute` could equally well be achieved by changing the implementation of `MyMethod' - or? Don't see the difference. – Gerard Feb 19 '14 at 21:49
  • @Gerard: It's all about the semantics, both the command and the method get it from their respective names which informs which implementation allows for which changes. As mentioned: If you introduce a read/unread status to messages you will not implement the logic to mark a message as read in the `DisplayMessage` method but add it to `Execute` of a `SelectMessageCommand`, hence at that point there is a fork at which calling the command has a different effect than calling `DisplayMessage`. The only thing you need to keep in mind is whether the command is semantically identical to the methods. – H.B. Feb 19 '14 at 22:51
  • @H.B. Thanks for your patience, apparantly I am not much of a "semanticus" - but some day I might just run into such an issue. – Gerard Feb 19 '14 at 23:20
  • For Xamarin.Forms, since ``BindingContext`` is similar to ``DataContext`` ``` var vm = this.BindingContext as ViewModels.DatabaseSyncViewModel; if (vm.OnLoaded.CanExecute()) vm.OnLoaded.Execute(); ``` – Damian Apr 24 '19 at 20:02
  • @H.B. doesn't casting DataContext break MVVM? At least that's what I learned from here https://stackoverflow.com/questions/72036638/c-sharp-wpf-mvvm-unable-to-set-property-value-from-view – sanya Apr 29 '22 at 16:53
  • 1
    @sanya: That is a common misconception. The view has to know what the view-model is, otherwise bindings would not work either. Generally you just try to avoid code-behind because it is less declarative and a bit more messy. The other way around would be a violation (the view-model accessing the view), in the original design pattern the same view-model might have multiple different views, though in practice it tends to be 1 to 1. – H.B. Apr 29 '22 at 18:09
10

Preface: Without knowing more about your requirements, it seems like a code smell to execute a command from code-behind upon loading. There has to be a better way, MVVM-wise.

But, if you really need to do it in code behind, something like this would probably work (note: I cannot test this at the moment):

private void UserControl_Loaded(object sender, RoutedEventArgs e)     
{
    // Get the viewmodel from the DataContext
    MyViewModel vm = this.DataContext as MyViewModel;

    //Call command from viewmodel     
    if ((vm != null) && (vm.MyCommand.CanExecute(null)))
        vm.MyCommand.Execute(null);
} 

Again - try to find a better way...

Alain
  • 26,663
  • 20
  • 114
  • 184
Wonko the Sane
  • 10,623
  • 8
  • 67
  • 92
  • 4
    Upon searching on the topic, there really isn't any easy way, and the general consensus I've seen is a little code behind never killed anyone. – Kevin DiTraglia Apr 12 '12 at 15:54
  • 2
    @KDiTraglia - true, but generally speaking, the "little code behind" generally refers to actions that effect only the View itself (i.e. things like selecting all the text in a text box when it gains focus). Here, you are interacting directly with the ViewModel from the View's code-behind, which breaks the MVVM principle. – Wonko the Sane Apr 12 '12 at 17:25
  • @WonkotheSane I disagree. The view already knows about the ViewModel by binding to its commands and properties, so referencing the ViewModel from the codebehind is just as ok as doing it from XAML. The ViewModel shouldn't know about the the View though, that would definitely violate the MVVM principle. – Shahin Dohan Dec 04 '20 at 14:00
  • 1
    @ShahinDohan - this may have evolved a bit in the last 8 years :) but I think the basic principle remains. If you need to interact in code-behind for things like confirmation dialogs or the like, that's fine. However, if you're interacting with the ViewModel in code behind to do business logic, that really still violates the idea. At least that's my opinion. – Wonko the Sane Dec 04 '20 at 15:16
2

I have a more compact solution that I want to share. Because I often execute commands in my ViewModels, I got tired of writing the same if statement. So I wrote an extension for ICommand interface.

using System.Windows.Input;

namespace SharedViewModels.Helpers
{
    public static class ICommandHelper
    {
        public static bool CheckBeginExecute(this ICommand command)
        {
            return CheckBeginExecuteCommand(command);
        }

        public static bool CheckBeginExecuteCommand(ICommand command)
        {
            var canExecute = false;
            lock (command)
            {
                canExecute = command.CanExecute(null);
                if (canExecute)
                {
                    command.Execute(null);
                }
            }

            return canExecute;
        }
    }
}

And this is how you would execute command in code:

((MyViewModel)DataContext).MyCommand.CheckBeginExecute();

I hope this will speed up your development just a tiny bit more. :)

P.S. Don't forget to include the ICommandHelper's namespace too. (In my case it is SharedViewModels.Helpers)

Stefan Vasiljevic
  • 4,315
  • 1
  • 18
  • 17
1

Try this:

private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
    //Optional - first test if the DataContext is not a MyViewModel
    if( !this.DataContext is MyViewModel) return;
    //Optional - check the CanExecute
    if( !((MyViewModel) this.DataContext).MyCommand.CanExecute(null) ) return;
    //Execute the command
    ((MyViewModel) this.DataContext).MyCommand.Execute(null)
}
Alain
  • 26,663
  • 20
  • 114
  • 184
  • 2
    You should not call a Command without ensuring that it can be executed first. – H.B. Apr 12 '12 at 15:52
  • If you are only using the CanExecute to determine whether the user can execute it (i.e. Binding to a button's enabled state) there's nothing wrong with it. – Alain Apr 12 '12 at 15:55
  • 3
    With a button the control ensures that the command is never executed carelessly, if you execute it manually you need to take care of that yourself. – H.B. Apr 12 '12 at 15:56
1

To call a command in code behind, you can use this code line

e.g.: Call a Button command

Button.Command?.Execute(Button.CommandParameter);
Junaid Pathan
  • 3,850
  • 1
  • 25
  • 47
luka
  • 605
  • 8
  • 15
0

You also might have embedded your code in any MessaginCenter.Subscribe and work with MessagingCenter model. If you intend only execute something from code behind instead of clicking in a view button with Command property, it worked perfectly to me.

I hope it helps someone.