Ответ 1
Это мое скромное решение MVP и ваши конкретные проблемы.
Первый, все, что пользователь может взаимодействовать или просто показывать, - это представление. Законы, поведение и характеристики такого вида описываются интерфейсом. Этот интерфейс может быть реализован с использованием пользовательского интерфейса WinForms, пользовательского интерфейса консоли, веб-интерфейса или даже без интерфейса (обычно при тестировании ведущего) - конкретная реализация просто не имеет значения, если она подчиняется законам интерфейса представления.
Второй, просмотр всегда контролируется ведущим. Законы, поведение и характеристики такого ведущего также описываются интерфейсом. Этот интерфейс не заинтересован в реализации конкретного представления, если он подчиняется законам его интерфейса представления.
Третий, поскольку ведущий управляет своим представлением, чтобы минимизировать зависимости, на самом деле нет никакой выгоды в том, что представление вообще ничего не знает о его ведущем. Там заключен договор между презентатором и точкой зрения, который указан интерфейсом представления.
Последствия Третий:
- Ведущий не имеет каких-либо методов, которые может вызвать вид, но в представлении есть события, на которые может подписаться ведущий.
- Ведущий знает свое мнение. Я предпочитаю выполнить это с помощью инъекции конструктора на конкретном презентаторе.
- Представление не имеет представления о том, что ведущий контролирует его; ему никогда не будет предоставлен какой-либо ведущий.
Для вашей проблемы приведенное выше может выглядеть так в несколько упрощенном коде:
interface IConfigurationView
{
event EventHandler SelectConfigurationFile;
void SetConfigurationFile(string fullPath);
void Show();
}
class ConfigurationView : IConfigurationView
{
Form form;
Button selectConfigurationFileButton;
Label fullPathLabel;
public event EventHandler SelectConfigurationFile;
public ConfigurationView()
{
// UI initialization.
this.selectConfigurationFileButton.Click += delegate
{
var Handler = this.SelectConfigurationFile;
if (Handler != null)
{
Handler(this, EventArgs.Empty);
}
};
}
public void SetConfigurationFile(string fullPath)
{
this.fullPathLabel.Text = fullPath;
}
public void Show()
{
this.form.ShowDialog();
}
}
interface IConfigurationPresenter
{
void ShowView();
}
class ConfigurationPresenter : IConfigurationPresenter
{
Configuration configuration = new Configuration();
IConfigurationView view;
public ConfigurationPresenter(IConfigurationView view)
{
this.view = view;
this.view.SelectConfigurationFile += delegate
{
// The ISelectFilePresenter and ISelectFileView behaviors
// are implicit here, but in a WinForms case, a call to
// OpenFileDialog wouldn't be too far fetched...
var selectFilePresenter = Gimme.The<ISelectFilePresenter>();
selectFilePresenter.ShowView();
this.configuration.FullPath = selectFilePresenter.FullPath;
this.view.SetConfigurationFile(this.configuration.FullPath);
};
}
public void ShowView()
{
this.view.SetConfigurationFile(this.configuration.FullPath);
this.view.Show();
}
}
В дополнение к вышесказанному, обычно у меня есть базовый интерфейс IView
, в котором я помещаю Show()
и любое представление владельца или заголовка, которое, как правило, извлекает мои взгляды.
На ваши вопросы:
1. Когда загружается winform, он должен получить treeview. Правильно ли я полагаю, что представление должно поэтому вызвать такой метод, как: presenter.gettree(), это, в свою очередь, будет делегировать модели, которая будет получать данные для древовидной структуры, создавать ее и настраивать, возвращать ее в ведущий, который, в свою очередь, перейдет к представлению, которое затем просто назначит его, скажем, панели?
Я бы назвал
IConfigurationView.SetTreeData(...)
изIConfigurationPresenter.ShowView()
, прямо перед вызовомIConfigurationView.Show()
2. Будет ли это одинаковым для любого управления данными в Winform, поскольку у меня также есть datagridview?
Да, я бы назвал
IConfigurationView.SetTableData(...)
для этого. Это зависит от вида для форматирования данных, предоставленных ему. Ведущий просто подчиняется контракту на просмотр, что ему нужны табличные данные.
3. Мое приложение имеет несколько классов моделей с одной и той же сборкой. Он также поддерживает архитектуру плагина с плагинами, которые необходимо загружать при запуске. Будет ли вид просто вызвать метод презентатора, который, в свою очередь, вызовет метод, который загружает плагины и отображает информацию в представлении? Какой уровень затем будет контролировать ссылки плагина. Будет ли представление содержать ссылки на них или докладчика?
Если плагины связаны с просмотром, представления должны знать о них, но не ведущие. Если все они связаны с данными и моделью, то представление не должно иметь ничего общего с ними.
4. Правильно ли я полагаю, что представление должно обрабатывать каждую вещь о представлении, от цвета дерева node, размера datagrid и т.д.?
Да. Подумайте об этом как докладчик, предоставляющий XML, который описывает данные и представление, которое берет данные, и применяет к нему таблицу стилей CSS. В конкретном плане ведущий может называть
IRoadMapView.SetRoadCondition(RoadCondition.Slippery)
, и представление затем отображает дорогу в красный цвет.
Как насчет данных для щелкнутых узлов?
5. Если при нажатии на treenodes я должен передать конкретный node ведущему, а затем из того, что ведущий будет определять, какие данные ему нужны, а затем спрашивает модель для этих данных, прежде чем представить его обратно в представление?
Если возможно, я бы передал все данные, необходимые для представления дерева в виде одним выстрелом. Но если некоторые данные слишком велики для передачи с самого начала или если они динамичны по своей природе и нуждаются в "последнем снимке" из модели (через презентатора), я бы добавил что-то вроде
event LoadNodeDetailsEventHandler LoadNodeDetails
к интерфейсу представления, так что ведущий может подписаться на него, извлеките детали из node вLoadNodeDetailsEventArgs.Node
(возможно, через свой идентификатор какого-либо типа) из модели, чтобы представление могло обновлять отображаемые данные node, когда обработчик события делегат возвращается. Обратите внимание, что асинхронные шаблоны могут потребоваться, если выборка данных может быть слишком медленной для хорошего пользовательского опыта.