Можно ли использовать 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 отлично работал.
Если вы действительно обеспокоены совместным использованием кода для нескольких типов проектов, лучше попробовать и поместить ваш общий код в типичную библиотеку классов типа "Бизнес-слой", а не в модель вида.