Це мій скромний погляд на 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()
{
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
{
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. Коли вінформ завантажується, він повинен отримати вигляд дерева. Чи правильно я вважаю, що подання, отже, повинно викликати такий метод, як: presenter.gettree (), це, в свою чергу, делегує моделі, яка отримає дані для перегляду дерева, створить їх і налаштує, поверне в ведучий, який у свою чергу перейде до подання, яке потім просто призначить його, скажімо, панелі?
Я б назвав IConfigurationView.SetTreeData(...)
з IConfigurationPresenter.ShowView()
, прямо перед викликомIConfigurationView.Show()
2. Чи буде це однаково для будь-якого елемента керування даними на Winform, оскільки я також маю datagridview?
Так, я б закликав IConfigurationView.SetTableData(...)
до цього. Формат даних, які йому надаються, залежить від подання. Ведучий просто виконує угоду подання щодо того, що йому потрібні табличні дані.
3. Мій додаток має ряд класів моделей з однаковим складанням. Він також підтримує архітектуру плагінів із плагінами, які потрібно завантажувати під час запуску. Чи просто вигляд викликав би метод презентатора, який, у свою чергу, викликав би метод, який завантажує плагіни та відображає інформацію у поданні? Який рівень тоді контролюватиме посилання на плагіни. У поданні міститься посилання на них чи на ведучого?
Якщо плагіни пов’язані з переглядом, тоді перегляди повинні знати про них, але не про ведучого. Якщо всі вони стосуються даних та моделі, тоді подання не повинно мати до них ніякого відношення.
4. Чи правильно я вважаю, що подання повинно обробляти все, що стосується презентації, від кольору вузла дерева до розміру сітки даних тощо?
Так. Подумайте про це як про презентатора, який надає XML, що описує дані та подання, яке бере дані, і застосовує до них таблицю стилів CSS. Якщо говорити конкретно, ведучий може зателефонувати, IRoadMapView.SetRoadCondition(RoadCondition.Slippery)
і вигляд надає дорогу червоному кольору.
А як щодо даних для клацаних вузлів?
5. Якщо, коли я натискаю на треноди, чи повинен я пройти через конкретний вузол до ведучого, а потім звідти ведучий буде обробляти, які дані йому потрібні, а потім запитує модель для цих даних, перш ніж представляти їх назад у подання?
Якщо можливо, я передав би всі дані, необхідні для представлення дерева у вигляді, одним пострілом. Але якщо деякі дані занадто великі, щоб їх можна було передавати з самого початку, або якщо вони динамічні за своєю суттю і потребують "останнього знімка" з моделі (через презентатор), тоді я додав би щось на зразок event LoadNodeDetailsEventHandler LoadNodeDetails
інтерфейсу перегляду, так що презентатор може підписатися на нього, отримати деталі вузла LoadNodeDetailsEventArgs.Node
(можливо, за допомогою свого певного ідентифікатора) з моделі, щоб подання могло оновити свої деталі, що відображаються, коли повертається делегат обробника подій. Зверніть увагу, що асинхронні шаблони цього можуть знадобитися, якщо отримання даних може бути надто повільним для хорошого користувацького досвіду.