Model view presenter, как передавать объекты между представлениями?
Edit: принят ответ Криса Холмса, но всегда готов к рефакторингу, если кто-то придумает лучший способ! Спасибо!
выполнение некоторых winforms с MVP, что является лучшим способом передать объект в другое представление.
скажем, у меня есть CustomerSearchView/Presenter
, на doubleClick я хочу показать CustomerEditView/Presenter
. Я не хочу, чтобы мой взгляд знал о модели, поэтому я не могу создать ctor, который принимает ICustomer
в параметрах.
мой рефлекс будет будь,
CustomerSearchView
создать новый CustomerEditView
, которые создают собственного докладчика.
Тогда мой CustomerSearchView
сделал бы что-то вроде :
var customerEditView = new CustomerEditView();
customerEditView.Presenter.Customer = this.Presenter.SelectedCustomer;
другой возможный подход был бы CustomerDTO
класса, и сделать CustomerEditView
, которые принимают один из этих CustomerDTO
, но я думаю, что это много работы что-то простое.
извините за основной вопрос, но все примеры, которые я могу найти, никогда не достигают этой точки, и это проект brownfield, и используемый до сих пор подход дает мне головная боль...
5 ответов
Я не знаю точно, как вы показываете свои взгляды, поэтому немного сложно дать вам конкретный совет здесь. Вот как я делал это раньше:
мы сделали так, чтобы CustomerSearchViewPresenter запустил событие, подобное OpenCustomer (customerId). (Это предполагает, что в вашем представлении поиска есть только несколько частей данных клиента, и customerId будет одним из них. Если в представлении поиска перечислены все объекты клиента, можно вызвать OpenCustomer(заказчик). Но я бы не стал создавать вид поиска и позволять ему заполняться целыми объектами... Мы сохраняем наши представления поиска легкими с точки зрения данных.)
где-то еще в приложении есть обработчик событий, который прослушивает событие OpenCustomer() и выполняет задачу создания нового CustomerEditView w/ Presenter (и я собираюсь отложить свой контейнер IoC, чтобы сделать это для меня, поэтому мне не нужно использовать ключевое слово "new" в любом месте). После создания представления мы можем передайте идентификатор (или объект customer) новому CustomerEditView, а затем покажите его.
этот класс, который отвечает за перечисление события OpenCustomer () и выполняет создание CustomerEditView, обычно является своего рода классом контроллера в нашем приложении.
чтобы еще больше упростить эту ситуацию, я сделал это другим способом: я создаю CustomerSearchView (& presenter) и CustomerEditView (& presenter) при запуске приложения или модуля. Когда CustomerSearchView должен открыть клиента для редактирования, CustomerEditView становится ответчиком на событие OpenCustomer и загружает данные в себя и знает, как показать себя в любом контейнере, который он должен делать.
Итак, есть несколько способов сделать это.
Как насчет:
//In CustomerSearchPresenter
var presenter = new CustomerEditPresenter();
var customerEditView = new CustomerEditView(presenter);
presenter.SetCustomer(customer);
//In CustomerEditPresenter
public void SetCustomer(customer)
{
View.Name = customer.Name;
View.Id = customer.Id;
...
}
в think ваше представление поиска клиентов должно просто делегировать его ведущему, вам нужно выполнить действие.
есть несколько важных идей, чтобы получить естественный поток в любом коде MVP:
- - Это ведущий, который управляет видом, а не наоборот.
- из-за 1. представление не должно знать о существовании ведущего. Меньше зависимостей обычно означает более легкое обслуживание.
В C# я считаю, что события являются большим активом при отделении докладчиков от представлений. Подробнее в предыдущем ответе:Модель-Вид-ведущий в Приложения WinForms
Я бы посмотрел на MS Prism 4 и их приятный навигационный интерфейс. Также посмотрите на навигацию Silverlight и WCF. Они хорошо сделаны и обрабатывают такие вещи, как запрос пользователя на подтверждение из "грязных" форм с отменой.
Я бы посмотрел документацию PageFunction () в WCF, а также, как "вызвать" страницу с другой, и получить обратно информацию.
вот как это работает (javascript, извините):
пользователь дважды щелкает клиента в список клиентов:
CustomerList.onDblClick(customerId){
app.fireEvent('customerEditRequest', id)
}
...
app.onCustomerEditRequest(id){
this.mainRegion.requestNavigate('customers/edit', id);
}
если навигация для редактирования представления прошла успешно...
CustomerEditView.onNavigatedTo(context){
this.model.load(context.parameters.id));
}
CustomerEditView.onSaveButtonClick(){
this.model.save();
app.fireEvent('customerEdited', id);
}
...
app.onCustomerEdited(id){
app.mainRegion.requestNavigate('customerlist', id);
}
есть несколько разных способов сделать это:
отправить функцию обратного вызова в форму редактирования из списка клиентов. форма редактирования будет вызывать его, и вы делаете то, что хотите, когда он называется.
редактировать форма поднять на" customerEdited " событие, которое вы слушаете и реагируете на (нет приложения шина)
используйте шину событий всего приложения для централизованного управления событиями.
раньше я общался со своими взглядами с их докладчиками, но отошел от этого. Это не соответствует первоначальному определению шаблона (не причина сама по себе для отклонения только способствующего фактора для получения этих преимуществ). Представления в идеале должны быть как можно более тупыми и иметь как можно меньше зависимостей. View должен общаться с ведущим (любыми "наблюдателями") через делегатов/события/некоторый механизм" огонь и забыть". На самом деле, я ввел контроллер в MVP специально для перехвата событий просмотра и либо повторного запуска presenter (редко) для общения с Презентатором, либо для связи с системой или шиной событий, специфичной для презентатора, что позволяет мне изменять механизмы оповещения пользователя о действиях без касания представления. Однако нужно быть осторожным с шиной событий; довольно скоро вы начинаете бросать все события там, приложение становится болтливым/увязшим в обработке событий, а события-это не самые быстрые вещи .Сеть. Sunchronization добавленная забота, esp если ur приложение должно иметь более "разговорное" взаимодействие с вашим пользователем.
следует иметь в виду, что, хотя презентатор является usu view/process-specific, представления (и view-models) могут быть повторно использованы; наличие представления в отношениях сдерживания/делегирования с Презентатором сильно ограничивает его повторное использование. Это может быть уменьшено некоторым DI, но я нахожу контейнеры DI ненужной сложностью в большинстве случаев (так как я должен знать, как создавать объекты в любом случае и как часто вы меняете из объекта для другого семантически похожего после его создания/тестирования?). Конкретная зависимость никуда не уходит, кроме другого слоя/добавляет больше неясности/затрудняет отладку/трассировку. Был на" простоте "удар в последнее время, хотя, и в основном предпочитают делать мои на заводе / объектных творений / ORM сопоставлений для большинства приложений, так как есть usu" 1-к-1 " btw db таблицы / сущности и N потребность в дополнительной сложности универсального стороннего инструмента ORM, который по taht общий контекст / необходимость служить различные приложения должны сделать вещи сложнее, чем они должны быть, даже если вы понимаете, как они работают (не суть).
более того, для View все еще вполне возможно наблюдать модель в MVP (как в MVC), поэтому я бы не стал так быстро исключать это. Я не предпочитаю делать это сам, но это не "ломает" шаблон. На самом деле, я разработал что-то похожее на MVP около десяти лет назад, потому что мне не понравился "круговой цикл" между компонентами MVC (просмотр, зная о модели); я предпочитал иметь более чистое разделение и модель, которую исповедовали все эти шаблоны (включая MVC), а также желание сохранить вид как можно более тупым (наблюдение за моделью означало бы, что для обработки изменений модели потребуется больше интеллекта). В итоге я сделал что-то вроде MVVM и strategy patter, где я использовал "подструктуры" модели, чтобы перейти к представлению, служащему "уведомителями изменений". Это сохранило все, что касается цели, и гибкое / многоразовое (жесткое комбинация.)