2016-04-15 3 views
1

Мне интересно, вводит ли команда в модель плохую практику в MVVM. Например, у меня есть ListBox с Image и Button. Когда я нажимаю на Button, мне нужно открыть URL-адрес в браузере. Итак, мой код будет выглядеть следующим образом:MVVM - это команда в модели плохой практики?

<ListBox ItemSource="{Binding Items"> 
    <ListBox.ItemTemplate> 
     <DataTemplate> 
      <StackPanel> 
       <Image Source={Binding ImageSource} /> 
       <Button Content="Open url" Command={Binding OpenUrlCommand}"/> 
      </StackPanel> 
     </DataTemplate> 
    </Listbox.ItemTemplate> 
</ListBox> 

ViewModel:

class MainViewModel:BaseViewModel 
{ 
    public ObservableCollection<Model> Items {get;set;} 
} 

Модель:

class Model 
{ 
    public string ImageSource {get;set;} 

    public string Url {get;set;} 

    public ICommand OpenUrlCommand {get;set;} 

    public Model() 
    { 
     OpenUrlCommand = new RelayCommand(openUrl); 
    } 

    public void openUrl() 
    { 
     Process.Start(Url); //Open url in browser 
    } 
} 

Это нормально, или я должен двигаться OpenUrlCommand к MainViewModel?

+0

Что является причиной, чтобы сделать это? – StepUp

+0

Я просто задаюсь вопросом, где должен быть OpenUrlCommand в ViewModel или Model –

ответ

5

Вы на самом деле должны реализовать метод в модели, но команда в ViewModel. Это будет гораздо более согласовано с архитектурой MVVM и в этом случае не будет никакой дополнительной работы для вас.

В вашей ViewModel:

class MainViewModel : BaseViewModel 
{ 
    private Model _model;  

    ICommand OpenUrlCommand { get { return new RelayCommand(_model.openUrl); } } 

    // ... 
} 

Если вы хотите "отправить" некоторые URL из View, вы можете использовать CommandParameter для этого, и есть набранный RelayCommand.

UPDATE: Обратите внимание, что, так как DataTemplate, где связывание проживает команда является ItemTemplate, вы должны реализовать команду в какой-то ItemViewModel, а не в MainViewModel. Затем сделать ItemsObservableCollection<ItemViewModel> вместо ObservableCollection<Model> и инициализировать коллекцию так:

IEnumerable<Model> models= getSomeModelsToStartWith(); 
var Items = new ObservableCollection<ItemViewModel>(models.Select(m => new ItemViewModel(m)); 
+0

Может ли разработчик downvoter оставить комментарий? – heltonbiker

+0

@ASh ожидается, что каждый ViewModel имеет ссылку на некоторую модель, обычно в виде поля, вводимого через конструктор или сеттер. Но главное: ViewModel содержит Command; Команда делегирует действие модели, будь то «модель» или элемент из списка. Поле '_model' является лишь иллюстративным примером. – heltonbiker

+0

@ASh, когда вы помещаете привязку внутри «ItemTemplate», команда автоматически привязывается к самому элементу (обычно это своего рода «ItemViewModel»). Это означает, что он должен быть реализован в «ItemViewModel», фактически, а не в «MainViewModel». – heltonbiker