Как внедрить действие в команду с помощью Ninject?

На самом деле изучает шаблон команд и находит его довольно интересным. Я пишу WPF-приложение для Windows по архитектурному шаблону MVVM.

Я начал с этого поста, который объясняет основы.

Теперь, когда я смог разбить действия пользователя на команды, я подумал, что было бы здорово добавить нужные мне команды. Я заметил, что команды находятся в ViewModel в первой статье, на которую есть ссылки, поэтому я подумал, что было бы здорово, если бы я мог использовать их вдоль Ninject и фактически внедрить свою команду в мою модель представления, используя привязку, которая будет выглядеть следующим образом:

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

Но тогда, что положить сюда??? Ожидаемый ответ - метод. Большой! Мне просто нужен метод, чтобы положить туда.

Поскольку первая статья просто инициализирует свои команды в конструкторе ViewModel, легко сказать, какой метод должен быть выполнен при вызове команды execute.

Но изнутри CompositionRoot? Здесь не место для метода, который будет делать что-то еще, кроме связывания типов, через какой-либо контейнер DI, который вы используете!

Итак, теперь я наткнулся на шаблон перехватчика, используя Ninject Extensions. Похоже, что это может удовлетворить мои требования, и здесь есть некоторая путаница, если я могу сказать. Не то чтобы статьи сбивают с толку, это не так. Я не совсем понимаю!

Также есть ответ от BatteryBackupUnit, который всегда задает отличные ответы.

Но сейчас я не вижу, как все это склеить! Смиренно, я потерян.

Итак, вот мой код.

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;
}

Интересно, будет ли лучше использовать Property Injection, хотя я склонен не использовать все это?

Допустим, у меня есть CategoriesManagementView это вызывает другое окно, скажем CreateCategoryView.Show(), а затем CreateCategoryView вступает во владение, пока пользователь не вернется в окно управления.

Команде Create затем нужно вызвать CreateCategoryView.Show(), и это то, что я пытался из 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;
}

Возможно, я слишком усложняю вещи, это то, что обычно случается, когда кто-то запутывается. знак равно

Мне просто интересно, может ли Ninject Interception Extension быть правильным инструментом для работы и как его эффективно использовать?

1 ответ

Я создал простой пример команды, взаимодействующей с внедренным сервисом. может не скомпилироваться, так как я ухожу из памяти. Может быть, это может помочь вам.

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);
    }
}


}
Другие вопросы по тегам