2015-12-20 3 views
1

Я создаю приложение с Simple Injector в WPF, и я столкнулся с проблемой, когда хочу, чтобы мои модели вводили в мои ViewModels во время выполнения. Например, скажем, у меня есть окно для редактирования пользователей, для которых требуется ViewModel с пользовательской моделью. Эта пользовательская модель выбирается из списка и затем вводится в конструктор ViewModel. Как я могу получить эти данные в ViewModel с помощью простого инжектора? Возможно ли это? Я полагаю, что если возможно, я бы использовал какую-то форму фабрики? Я обсуждал использование Simple Injector для всех, кроме моих MVVM-компонентов, в качестве обходного пути, то есть, если я не смогу найти хорошее решение.Введенные данные разрешили модели во время выполнения с помощью простого инжектора

Если я должен опубликовать какой-либо пример кода или что-то в этом духе, чтобы дать более четкое определение проблемы, дайте мне знать. Это мой первый запуск с контейнером DI, и я хочу понять, как наилучшим образом разработать мое приложение с одним.

ответ

3

Использование предпочтительного подхода, к которому вы стремитесь, действительно невозможно. Это потому, что ваш дизайн не оптимален. Как вы можете прочитать here ввод данных во время выполнения в компоненты вашего приложения является анти-шаблоном.

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

Таким образом, вы могли бы решить эту проблему, как:

public interface IViewModel<T> 
{ 
    void EditItem(T item); 
} 

class UserEditViewModel : IViewModel<User> 
{ 
    public void EditItem(User item) 
    { 
     // bind properties etc... 
    } 
} 

Вы обычно впрыскивают IViewModel<User> в своем мастер-ViewModel пользователя.

На основе моделей this и this вы можете представить себе гораздо более гибкое решение. Если вы увидите редактирование пользователя как выполнение команды, которую вы просто запускаете и возвращаете, когда она будет завершена, вы можете определить инфраструктурный компонент a la the QueryProcessor из ссылки. Это станет EditProcessor, который обрабатывает все ваши операции редактирования в вашем приложении. Реализация довольно проста и будет выглядеть примерно так:

class EditProcessor : IEditProcessor 
{ 
    private readonly Container container; 

    public EditProcessor(Container container) 
    { 
     this.container = container; 
    } 

    public void EditItem<T>(T item) 
    { 
     var viewModel = typeof (IViewModel<>).MakeGenericType(typeof (T)); 
     dynamic instance = container.GetInstance(viewModel); 

     instance.EditItem((dynamic) item); 
    } 
} 

Теперь везде вам нужно изменить некоторые модели, вы только инъекционные IEditProcessor и вызвать

this.editProcessor.EditItem(yourItem); 

Эта простая реализация EditProcessor может быть продлен будет всевозможные приятные функции, такие как создание резервной копии элемента перед редактированием, поэтому пользователь может отменить редактирование, например.

Если вы используете какой-либо набор инструментов MVVM для привязки своего вида к своей модели просмотра, это также станет местом, где вы можете принести свой контейнер DI и набор инструментов MVVM с помощью латиницы.

+0

Очень приятно, спасибо! – Carson

+0

У меня есть вопрос по этому вопросу. Как вы думаете, как мне показалось, что я привязался к этой модели? Скажем, у меня есть окно с конструктором, который принимает IViewModel , что я должен сделать, чтобы подключить все, или мне нужно, чтобы модель модели отображала это окно? Я видел, что это случалось. Я не использую инструментарий MVVM, поэтому мне нужно все это выяснить вручную. – Carson

+1

Учитывая определенную модель ViewModel, как бы вы нашли правильный просмотр? У вас есть какая-то конвенция? Наверное, по твоему вопросу ты этого не делаешь. Есть несколько способов сделать это. Если вы дадите мне какое-то направление, я могу отредактировать свой ответ с некоторыми примерами. –

1

Вам не следует вводить модели в модель ViewModel.

Звучит скорее как сборщик событий/мессенджер. Вы вводите агрегатор событий в свои модели просмотра и подписываетесь на определенное событие и поднимаете его из другого ViewModel.

public class CustomersViewModel 
{ 
    private readonly IEventAggregator eventAggregator; 

    public CustomersViewModel(IEventAggregator eventAggregator) 
    { 
     if(eventAggregator==null) 
     { 
      throw new ArgumentNullException("eventAggregator"); 
     } 

     this.eventAggregator = eventAggregator; 
    } 

    private Customer selectedCustomer; 
    public Customer SelectedCustomer 
    { 
     get { return selectedCustomer; } 
     set 
     { 
      if(selectedCustomer!=value) 
      { 
       selectedCustomer = value; 
       eventAggregator.Publish(new CustomerSelectedEvent(selectedCustomer); 
      } 
     } 
    } 
} 

public class CustomerOrdersViewModel 
{ 
    private readonly IEventAggregator eventAggregator; 
    private readonly IOrderRepository orderRepository; 

    private ObservableCollection<Order> orders; 
    public ObservableCollection<Order> Orders { 
     get { return orders; } 
     set 
     { 
      if(orders != value) 
      { 
       orders = value; 
       OnPropertyChanged("Orders"); 
      } 
     } 
    } 

    public CustomerDetailViewModel(IEventAggregator eventAggregator, IOrderRepository orderRepository) 
    { 
     if(eventAggregator==null) 
     { 
      throw new ArgumentNullException("eventAggregator"); 
     } 

     this.eventAggregator = eventAggregator; 
     this.eventAggregator.Subscribe<CustomerSelectedEvent>(OnCustomerSelected); 
     ... 
    } 

    private async void OnCustomerSelected(CustomerSelectedEvent event) 
    { 
     Orders = new ObservableCollection<Order>(await orderRepository.GetOrdersByCustomer(event.Customer.Id); 
    } 
} 

Если SelectedCustomerEvent будет простым классом POCO.

public class SelectedCustomerEvent 
{ 
    public Customer Customer { get; } 

    public SelectedCustomerEvent(Customer customer) 
    { 
     // C# 6.0, otherwise add a private setter 
     Customer = customer; 
    } 
} 

Реализация агрегатор событий немного выходит за рамки, но есть рамки, которые приходят с агрегаторами посланника/событий (Prism PubSubEvents, например).

+0

Интересный подход. Я предположил, что моя концепция была в некотором роде ошибочной, но я не был уверен, как это сделать и как ее заменить. Благодаря! – Carson

+0

Как бы вы показали модальный диалог для редактирования пользователя с использованием этого подхода? –

+0

Это сложная часть. Один из способов сделать это - использовать Dialog или навигационную службу, вы передаете интерфейс на вашем уровне ViewModel и выполняете конкретную реализацию в своей сборке View/Application (при условии, что вы используете MVVM, разбивая приложение на как минимум 3 сборки для модели , viewmodel и view/application). Другой подход рассматривается в платформе Prism 5.0/6.0, с InteractionRequest https://msdn.microsoft.com/en-us/library/gg405494(v=pandp.40).aspx, с которой сложно начать работу, но может быть довольно мощный, как только вы овладеете им. – Tseng

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