2015-11-12 5 views
0

Я создаю приложение браузера WPF с шаблоном MVVM.Передача параметра конструктору в ViewModel

У меня есть первая страница (ConsultInvoice) с dataGrid. Когда я дважды нажимаю на одну из строк, я хочу перейти на другую страницу (EditInvoice), передав выбранную строку в аргументе моему конструктору.

Я знаю, если я хочу делать что-то правильно, я должен использовать инъекцию зависимостей, но я действительно не вижу, как его использовать здесь.

Как я могу просто передать этот конструктор?

ConsultInvoiceViewModel

private Invoice _selected; 
public Invoice Selected 
{ 
    get 
    { 
     return _selected; 
    } 
    set 
    { 
     _selected = value; 
     OnPropertyChanged("Selected"); 
    } 
} 

private void Edit() 
{ 
    EditInvoiceViewModel editInvoice = new EditInvoiceViewModel(Selected); 
    /* doing something here*/ 
} 

public ICommand EditCommand 
{ 
    get 
    { 
     return editCommand ?? (editCommand = new RelayCommand(p => this.Edit(), p => this.CanEdit())); 
    } 
} 

EditInvoiceViewModel

public class EditInvoiceViewModel : ViewModelBase 
{ 
    public Context ctx = new Context(); 
    Invoice invoice; 
    PreInvoice preInvoice; 
    #region properties 
    private ObservableCollection<PreInvoice> collection; 
    public ObservableCollection<PreInvoice> Collection 
    { 
     get 
     { 
      return collection; 
     } 
     set 
     { 
      collection = value; 
      OnPropertyChanged("Collection"); 
     } 
    } 
    #endregion 
    public EditInvoiceViewModel(Invoice inv) 
    { 
     /* do stuff*/ 
    } 
} 
+0

Возможно, это только я, но я немного смущен. Вы уже передаете параметр (Selected) в конструктор (EditInvoiceViewModel (Invoice inv)) в ViewModel (ConsultInvoiceViewModel)? Что именно вы спрашиваете? – Rowbear

+0

@Rowbear да, но целью является открытие нового EditInvoiceView.xaml, и он принимает только конструктор по умолчанию. То, что я пытаюсь сделать, не работает. – Cantinou

+0

ах! Понимаю. Вы планируете показывать EditInvoiceView как всплывающее окно или новое окно?Как вы планируете контролировать показ EditInvoiceView? С помощью только .Show() /. ShowDialog()? Имеет ли смысл использовать все возможные счета от ConsultInvoiceViewModel для совместного использования одного вида? Или вы сможете редактировать сразу несколько счетов-фактур? – Rowbear

ответ

0

В принципе вы должны избегать прохождения таких параметров в конструктор ViewModels, так как проводка его Инверсия управления/Dependency Injection становится боль. Хотя вы можете использовать шаблон Abstract Factory для разрешения объектов с параметрами времени выполнения, это imho не подходит для ViewModels.

Вместо этого я всегда предлагаю использовать форму навигации, похожую на то, как шаблоны Microsoft & Практика команда сделала с Prism. Там у вас есть интерфейс INavigationAware, который можно реализовать в ViewModels. Он имеет 2 метода: NavigateTo и NavigateFrom.

И есть навигационное обслуживание. Навигационная служба переключит представления и до переключения вызова NavigateFrom в текущую ViewModel (если она ее реализует). Можно использовать ее, чтобы проверить, сохранены ли данные и, при необходимости, отменить навигацию. После того, как новый просмотр был загружен и назначен ViewModel к нему, называем NavigateTo в недавно ViewModel управление судном.

Здесь вы бы передать параметры, необходимые для ViewModel, в вашем случае invoiceId. Старайтесь избегать прохождений целых моделей или сложных объектов. Используйте invoiceid для извлечения данных счетов и для заполнения вашего редактирования ViewModel.

Реализация базового элемента из моего прежнего ответа (вы можете найти here):

public interface INavigationService 
{ 
    // T is whatever your base ViewModel class is called 
    void NavigateTo<T>() where T ViewModel; 
    void NavigateToNewWindow<T>(); 
    void NavigateToNewWindow<T>(object parameter); 
    void NavigateTo<T>(object parameter); 
} 

public class NavigationService : INavigationService 
{ 
    private IUnityContainer container; 
    public NavigationService(IUnityContainer container) 
    { 
     this.container = container; 
    } 
    public void NavigateToWindow<T>(object parameter) where T : IView 
    { 
     // configure your IoC container to resolve a View for a given ViewModel 
     // i.e. container.Register<IPlotView, PlotWindow>(); in your 
     // composition root 
     IView view = container.Resolve<T>(); 

     Window window = view as Window; 
     if(window!=null) 
      window.Show(); 

     INavigationAware nav = view as INavigationAware; 
     if(nav!= null) 
      nav.NavigatedTo(parameter); 
    } 
} 

// IPlotView is an empty interface, only used to be able to resolve 
// the PlotWindow w/o needing to reference to it's concrete implementation as 
// calling navigationService.NavigateToWindow<PlotWindow>(userId); would violate 
// MVVM pattern, where navigationService.NavigateToWindow<IPlotWindow>(userId); doesn't. There are also other ways involving strings or naming 
// convention, but this is out of scope for this answer. IView would 
// just implement "object DataContext { get; set; }" property, which is already 
// implemented Control objects 
public class PlotWindow : Window, IView, IPlotView 
{ 
} 

public class PlotViewModel : ViewModel, INotifyPropertyChanged, INavigationAware 
{ 
    private int plotId; 
    public void NavigatedTo(object parameter) where T : IView 
    { 
     if(!parameter is int) 
      return; // Wrong parameter type passed 

     this.plotId = (int)parameter; 
     Task.Start(() => { 
      // load the data 
      PlotData = LoadPlot(plotId); 
     }); 
    } 

    private Plot plotData; 
    public Plot PlotData { 
     get { return plotData; } 
     set 
     { 
      if(plotData != value) 
      { 
       plotData = value; 
       OnPropertyChanged("PlotData"); 
      } 
     } 
    } 
} 

Пример интерфейса INavigationAware, используемого в Prism можно найти на projects github repository.

Это позволяет легко передавать параметр и async загрузить данные (там, где нет никакого чистый способ сделать это с помощью конструктора, так как вы не можете awaitasync операции внутри конструктора без блокировки, и делает этот вид вещей в конструкторе очень обескуражен).

Смежные вопросы