Можно ли использовать ICommand в виде-модели

Большинство приложений MVVM WPF, мы используем ICommand в модели представления. Но это относится к System.Windows.Input. поэтому модель представления теперь тесно связана с пространством имен System.Windows.Input. согласно моему пониманию, модель представления должна быть в состоянии использовать в обычном приложении winform С# или в asp.net-приложении.

Обычно мы используем следующие строки кода для команды с реализацией RelayCommand.

private RelayCommand testCommand;// or private ICommand testCommand;

public ICommand TestCommand
{
    get
    {
        return testCommand ?? 
            (testCommand = new RelayCommand(param => Test()));
    }
}

public void Test()
{

}

Я считаю, что нам нужно удалить все ICommand и использовать RelayCommand. Поэтому мы можем исключить пространство имен System.Windows из модели представления. поэтому окончательный код будет выглядеть следующим образом:

private RelayCommand testCommand;

public RelayCommand TestCommand
{
    get
    {
        return testCommand ?? 
            (testCommand = new RelayCommand(param => Test()));
    }
}

public void Test()
{

}

Любые предложения по этому подходу? или существует ли способ устранить пространство имен System.Windows из модели представления?

Ответ 1

Довольно просто избежать соединения ViewModel с ICommand, если хотите. Вероятно, неплохая идея, WPF, вероятно, пойдет на путь MFC в один прекрасный день. Overkill? возможно, но вот как:

На ваш взгляд:

<StackPanel>
    <Button Command="{Binding Path=MyCommand}"> Do it! Kill me Now!</Button>
    <TextBlock Text="{Binding Path=Message}"></TextBlock>
</StackPanel>

Внесите свой ViewModel в свой DataContext, возьмите на себя ответственность за собственные команды из модели вашего вида:

public class ViewModel : INotifyPropertyChanged
{
    public string Message { get; set; }
    public object MyCommand { get; set; }


    public void OnMyCommand(object parameter)
    {
        Message += "I Ran something" + Environment.NewLine;
    }

    public bool CanMyCommand(object parameter)
    {
        return true;
    }

    // Injected Native Command handler
    public ViewModel(ICommandFactory factory)
    {
        MyCommand = factory.CreateInstance(OnMyCommand, CanMyCommand);
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

Примечание. Я использую FODY для переплетения свойства изменить обработчик. INotifyPropertyChanged - это файл System.dll.

Теперь, Свяжите этот контракт:

public interface ICommandFactory
{
    object CreateInstance(Action<object> action, Func<object, bool> predicate);
}

... к тому, что даст вам собственный объект Command;

public class NativeCommand : ICommand
{
    private readonly Action<object> _action;
    private readonly Func<object, bool> _predicate;

    public NativeCommand(Action<object> action, Func<object, bool> predicate)
    {
        _action = action;
        _predicate = predicate;
    }

    public bool CanExecute(object parameter)
    {
        return _predicate(parameter);
    }

    public void Execute(object parameter)
    {
        _action(parameter);
    }

    public event EventHandler CanExecuteChanged;
}


public class NativeCommandFactory : ICommandFactory
{
    public object CreateInstance(Action<object> action, Func<object, bool> predicate)
    {
        return new NativeCommand(action, predicate);
    }
}

Bind<ICommandFactory>().To<NativeCommandFactory>();

Voilà, развязанные команды.

running

Также обратите внимание: ваша инъекция выполняется при первом запуске приложения. Ваша ViewModel отделена от любого контейнера IoC, который вы выберете.

Ответ 2

Любые предложения по этому подходу?

Это все еще не отделяет вас от System.Windows.Input, поскольку RelayCommand все еще должен реализовывать ICommand, даже если он косвенно реализует его.

Реализация ICommand в ViewModel является одной из тех вещей, которые, как правило, требуются для того, чтобы быть прагматичными. В идеале ICommand (или аналогичный интерфейс) был бы реализован в пространстве имен, которое не было специфичным для XAML. При этом он поддерживается непосредственно в Portable Class Libraries, поэтому он не привязан к определенной структуре (WPF, Silverlight, Phone и т.д.). ) столько же, сколько XAML.

Ответ 3

Хорошо, теоретически, вы в значительной степени правы. Было бы хорошо, если бы ICommand полностью не зависел от платформы.

Но с практической точки зрения, если вы используете MVVM в приложении WPF, есть довольно хороший шанс, что вы в любом случае зависите от привязки данных и данных datatemplating от WPF. Попытка вставить пользовательский интерфейс WinForms поверх чего-то подобного, вероятно, потребует значительных дополнительных усилий.

Я работал над некоторыми довольно крупными проектами WPF/MVVM в прошлом. Мы рассматривали MVVM как способ отделить конкретные детали пользовательского интерфейса от кода - не так, чтобы мы могли переключиться на WinForms/ASP.NET/независимо, но чтобы мы могли изменить внешний вид нашего пользовательского интерфейса (т.е. Редактировать XAML) без необходимости изменять ViewModels. В этом отношении MVVM отлично работал.

Если вы действительно обеспокоены совместным использованием кода для нескольких типов проектов, лучше попробовать и поместить ваш общий код в типичную библиотеку классов типа "Бизнес-слой", а не в модель вида.