0

Actually exploring the Command Pattern and finds it pretty interesting. I'm writing a WPF Windows App following the MVVM Architectural Pattern.

I've begun with these post which explain the basics.

Now that I was able to break user actions into commands, I thought this could be great to inject the commands that I want. I noticed that the commands are found into the ViewModel in the first referenced article, So I thought that would be great if I could use them along Ninject and actually inject my command into my view model using a binding that would look like the following:

kernel
    .Bind<ICommand>()
    .To<RelayCommand>()
    .WithConstructorArgument("execute", new Action<object>(???));

But then, what to put in here ???. The expected answer is a method. Great! I just need a method to be put in there.

Because the first article simply initialize its commands within the ViewModel constructor, it is easy to say what method should be executed on the command execute call.

But from within the CompositionRoot? This is no place to put a method that will do anything else than bind types together through whatever DI container you're using!

So now, I've come across the Interceptor Pattern using Ninject Extensions. This looks like it could suits my requirements, and there is a bit of confusion here, if I may say. Not that the articles are confusing, they're not. I'm confused!

Also, there is this answer from BatteryBackupUnit who always sets great answers.

But now, I can't see how to glue it all up together! Humbly, I'm lost.

So here's my code so far.

RelayCommand

public class RelayCommand : ICommand {
    public RelayCommand(Action<object> methodToExecute, Predicate<object> canExecute) {
        if(methodToExecute == null)
            throw new ArgumentNullException("methodToExecute");

        if(canExecute == null)
            throw new ArgumentNullException("canExecute");

        this.canExecute = canExecute;
        this.methodToExecute = methodToExecute;
    }

    public bool CanExecute(object parameter) {
        return canExecute != null && canExecute(parameter);
    }

    public event EventHandler CanExecuteChanged {
        add {
            CommandManager.RequerySuggested += value;
            canExecuteChanged += value;
        }
        remove {
            CommandManager.RequerySuggested -= value;
            canExecuteChanged -= value;
        }
    }

    public static bool DefaultCanExecute(object parameter) { return true; }
    public void Execute(object parameter) { methodToExecute(parameter); }
    public void OnCanExecuteChanged() {
        var handler = canExecuteChanged;
        if(handler != null) handler(this, EventArgs.Empty);
    }

    public void Destroy() {
        canExecute = _ => false;
        methodToExecute = _ => { return; };
    }

    private Predicate<object> canExecute;
    private Action<object> methodToExecute;
    private event EventHandler canExecuteChanged;
}

CategoriesManagementViewModel

public class CategoriesManagementViewModel : ViewModel<IList<Category>> {
    public CategoriesManagementViewModel(IList<Category> categories
        , ICommand changeCommand
        , ICommand createCommand
        , ICommand deleteCommand) : base(categories) {
        if(changeCommand == null) 
            throw new ArgumentNullException("changeCommand");

        if(createCommand == null)
            throw new ArgumentNullException("createCommand");

        if(deleteCommand == null)
            throw new ArgumentNullException("deleteCommand");

        this.changeCommand = changeCommand;
        this.createCommand = createCommand;
        this.deleteCommand = deleteCommand;
    }

    public ICommand ChangeCommand { get { return changeCommand; } }
    public ICommand CreateCommand { get { return createCommand; } }
    public ICommand DeleteCommand { get { return deleteCommand; } }

    private readonly ICommand changeCommand;
    private readonly ICommand createCommand;
    private readonly ICommand deleteCommand;
}

I wonder, would it be better off using Property Injection, though I tend not to use it all?

Let's say I have CategoriesManagementView that calls another window, let's say CreateCategoryView.Show(), and then the CreateCategoryView takes over until the user is back to the management window.

The Create Command then needs to call CreateCategoryView.Show(), and that is what I tried from within the CompositionRoot.

CompositionRoot

public class CompositionRoot {
    public CompositionRoot(IKernel kernel) {
        if(kernel == null) throw new ArgumentNullException("kernel");
        this.kernel = kernel;
    }

    // 
    // Unrelated code suppressed for simplicity sake.
    //

    public IKernel ComposeObjectGraph() {
        BindCommandsByConvention();
        return kernel;
    }

    private void BindCommandsByConvention() {
        //
        // This is where I'm lost. I can't see any way to tell Ninject
        // what I want it to inject into my RelayCommand class constructor.
        //
        kernel
            .Bind<ICommand>()
            .To<RelayCommand>()
            .WithConstructorArgument("methodToExecute", new Action<object>());

        // 
        // I have also tried:
        //
        kernel
            .Bind<ICommand>()
            .ToConstructor(ctx => 
                 new RelayCommand(new Action<object>(
                     ctx.Context.Kernel
                         .Get<ICreateCategoryView>().ShowSelf()), true);
        //
        // And this would complain that there is no implicit conversion
        // between void and Action and so forth.
        //
    }

    private readonly IKernel kernel;
}

Perhaps I am overcomplicating things, that is generally what happends when one gets confused. =)

I just wonder whether the Ninject Interception Extension could be the right tool for the job, and how to use it effectively?

Community
  • 1
  • 1
Will Marcouiller
  • 23,773
  • 22
  • 96
  • 162
  • I think injecting action is wrong approach. The Commands in your VM's should be using injected services inside the command methods. – vidalsasoon Mar 13 '15 at 14:55
  • Would this mean, for instance, that my `createCommand` parameter would be a class which in turn depends on my `CreateCategoryView` and then the ICommand.Execute would simply call the dependency's `Show()` method? – Will Marcouiller Mar 13 '15 at 15:07
  • you just need to declare command in your VM and bind to it. Ex: public DelegateCommand SignInCommand { get; private set; }. In your implementation, reference your injected service (your API, AuthenticationService etc.) – vidalsasoon Mar 13 '15 at 15:42
  • That's my intention, and I don't seem to find a way to work it. That is exactly what I have in my ViewModel, a property typed ICommand which access modifier is set to public, and then the ViewModel's command can be called through data binding. This, I understand. what I don't is how to build my command correctly. Does my command need to depend on my service directly? I guess... – Will Marcouiller Mar 13 '15 at 15:48
  • You should definately read [this blog post](https://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=91). The command pattern might not be the best pattern in your case. – Steven Mar 15 '15 at 17:01

1 Answers1

0

I created a simple example of a command interacting with an injected service. might not compile since i'm going from memory. Maybe this can help you.

public class TestViewModel
{
    private readonly IAuthenticationService _authenticationService;

    public DelegateCommand SignInCommand { get; private set; }

    public TestViewModel(IAuthenticationService authenticationService) //Inject auth service
    {
        _authenticationService = authenticationService

        SignInCommand = new DelegateCommand(OnSignInRequest)
    }

    private void OnSignInRequest(Action<bool> isSuccessCallback)
    {
        var isSuccess = _authenticationService.SignIn();

        isSuccessCallback(isSuccess);
    }
}


}
vidalsasoon
  • 4,365
  • 1
  • 32
  • 40