Я реализовал триаду MVP, используя шаблон пассивного представления, то есть представление содержит только простые методы получения и установки. Однако у меня возникли проблемы с разделением данных вида и модели. В частности, при обработке изменения состояния просмотра.
Триада используется, чтобы позволить пользователю выбрать деталь из списка. Список деталей предоставляется моделью, причем каждая деталь уникально идентифицируется уникальным идентификатором.
Допустим, детали выглядят так:
class Part
{
int ID; // this code uniquely identifies the part within the model
String partCode;
String description;
double voltage;
}
Представление отображает список для пользователя и позволяет ему выбрать деталь
Список отображается в DataGridView, и часть выбирается щелчком по строке в dataGridView.
Идентификатор не должен отображаться пользователю, равно как и напряжение, поэтому модель создает DataTable, который содержит только partCode и описание. Этот DataTable назначается презентатором свойству в представлении, которое сопоставляется со свойством DataSource DataGridView.
class Presenter
{
IView _view;
IModel _model;
//...///
_view.Data = _model.GetFilteredData();
}
class Model
{
public DataTable GetFilteredData()
{
// create a DataTable with the partCode and Description columns only
// return DataTable
}
}
class View //winform
{
public DataTable Data
{
set
{
this.dataGridView.Source = value;
}
}
}
Пока все хорошо. Представление отображает отфильтрованные данные в DataGridView.
У меня проблема с возвратом детали, выбранной пользователем.
Представление не знает уникального идентификатора, поскольку оно не отображается, а другая информация не может быть гарантированно уникальной - поэтому невозможно однозначно идентифицировать выбранную деталь.
По сути, я пытаюсь преобразовать данные вида (выбранную строку) в данные модели (выбранную деталь) без одного компонента, используя другие данные.
Пока у меня есть следующие решения:
1) Представлению передается DataTable, которое содержит идентификатор, а затем фильтрует отображение, чтобы оно не отображалось пользователю. Затем тривиально вернуть идентификатор для выбранной строки. Проблема здесь в том, что я теперь загрязнил вид непроверенной логикой (фильтрация дисплея).
2) Представление возвращает индекс строки, и модель сопоставляет этот индекс со строкой в исходных данных. Это будет означать, что порядок в представлении никогда не изменяется, что, хотя и возможно, ограничивает то, как представление может отображать (и манипулировать) данные. Это также загрязняет модель данными представления (индекс строки).
public int RowIndexSelected { get; private set; }
//...//
private void gridParts_CellEnter(object sender, DataGridViewCellEventArgs e)
{
if (SelectedPartChangedEvent != null)
{
RowIndexSelected = e.RowIndex;
SelectedPartChangedEvent();
}
}
3) Вариация (2). Создайте объект адаптера, который будет находиться между докладчиком и представлением. Переместите строку в код преобразования идентификатора из модели в адаптер. Затем докладчик обрабатывает событие изменения детали dataGridAdapters.
public PartSelectDataGridAdapter(IPartSelectView view, PartCollection data)
{
_view = view;
_data = data;
_view.SelectedPanelChangedEvent += HandleSelectedPartChanged;
}
void HandleSelectedPartChanged()
{
int id = _data[_view.RowIndexSelected].ID;
if (SelectedPartChanged != null)
{
SelectedPartChanged(id);
}
}
В настоящее время я учусь на 3, так как он тестируемый, защищает логику от представления и данные от модели и презентатора.
Как бы вы занялись этим - есть ли лучшее решение?