我已经使用被动视图模式实现了一个 MVP 三元组——即视图只包含简单的 getter 和 setter。但是,我无法分离视图数据和模型数据。特别是在处理视图状态的变化时。
三元组用于使用户能够从列表中选择一个部分。零件列表由模型提供,每个零件都由唯一的 id 唯一标识。
假设这些部分看起来像这样:
class Part
{
int ID; // this code uniquely identifies the part within the model
String partCode;
String description;
double voltage;
}
视图向用户显示列表并允许他们选择一个部分
该列表显示在 DataGridView 中,并通过单击 dataGridView 中的一行来选择一个部分。
ID 不会显示给用户,电压也不会显示给用户,因此模型会创建一个仅包含 partCode 和描述的 DataTable。此 DataTable 由演示者分配给视图上的一个属性,该属性映射到 DataGridView 的 DataSource 属性。
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;
}
}
}
到现在为止还挺好。View 在 DataGridView 中显示过滤后的数据。
我遇到的问题是返回用户选择的部分。
视图不知道唯一 ID,因为它不显示,并且不能保证其他信息是唯一的 - 因此无法唯一标识所选部件。
本质上,我正在尝试将视图数据(选定的行)转换为模型数据(选定的部分),而无需使用其他数据的一个组件。
到目前为止,我有以下解决方案:
1)视图被传递一个包含ID的DataTable,然后过滤显示,使其不显示给用户。然后返回所选行的 ID 就很简单了。这里的问题是我现在已经用未经测试的逻辑(显示过滤)污染了视图。
2) 视图返回行索引,模型将该索引与原始数据中的一行进行匹配。这意味着确保视图中的顺序永远不会改变,这虽然可能会限制视图如何显示(和操作)数据。这也会用视图数据(行索引)污染模型。
public int RowIndexSelected { get; private set; }
//...//
private void gridParts_CellEnter(object sender, DataGridViewCellEventArgs e)
{
if (SelectedPartChangedEvent != null)
{
RowIndexSelected = e.RowIndex;
SelectedPartChangedEvent();
}
}
3) (2) 的变体。创建一个适配器对象以位于演示者和视图之间。将行到 ID 转换代码从模型移动到适配器。演示者然后处理 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 学习,因为它是可测试的,将逻辑排除在视图之外,并将数据视图排除在模型和演示者之外。
您将如何解决这个问题 - 有没有更好的解决方案?