gpt4 book ai didi

c# - MVP 被动 View ——保持 View 数据和模型数据分离

转载 作者:行者123 更新时间:2023-11-30 16:32:09 29 4
gpt4 key购买 nike

我已经使用被动 View 模式实现了一个 MVP 三元组——即 View 只包含简单的 getter 和 setter。但是我在分离 View 数据和模型数据时遇到了问题。特别是在处理 View 状态的更改时。

三元组用于使用户能够从列表中选择一个部分。零件列表由模型提供,每个零件由唯一的 id 唯一标识。

假设这些部分看起来像这样:

class Part
{
int ID; // this code uniquely identifies the part within the model
String partCode;
String description;
double voltage;
}

View 向用户显示列表并允许他们选择一个部分

列表显示在 DataGridView 中,通过单击 dataGridView 中的一行来选择部分。

ID 和电压都不会显示给用户,因此模型创建了一个仅包含 partCode 和描述的 DataTable。此 DataTable 由演示者分配给映射到 DataGridView 的 DataSource 属性的 View 上的属性。

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 中显示过滤后的数据。

我遇到的问题是返回用户选择的部分。

View 不知道唯一 ID,因为它不会显示,并且不能保证其他信息是唯一的 - 因此无法唯一标识所选部分。

本质上,我正在尝试将 View 数据(选定的行)转换为模型数据(选定的部分),而无需一个组件使用其他数据。

到目前为止,我有以下解决方案:

1)向 View 传递一个包含ID的DataTable,然后过滤显示,使其不显示给用户。然后返回所选行的 ID 就很简单了。这里的问题是我现在用未经测试的逻辑(显示过滤)污染了 View 。

2) View 返回行索引,模型将该索引与原始数据中的一行匹配。这意味着确保 View 中的顺序永远不会改变,这虽然可能,但会限制 View 显示(和操作)数据的方式。这也会用 View 数据(行索引)污染模型。

    public int RowIndexSelected { get; private set; }

//...//

private void gridParts_CellEnter(object sender, DataGridViewCellEventArgs e)
{
if (SelectedPartChangedEvent != null)
{
RowIndexSelected = e.RowIndex;

SelectedPartChangedEvent();
}
}

3) (2) 的变体。创建一个适配器对象以位于呈现器和 View 之间。将行到 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,因为它是可测试的,将逻辑置于 View 之外,将 View 数据置于模型和演示者之外。

您将如何解决这个问题 - 有更好的解决方案吗?

最佳答案

我之前发布了一个简单的解决方案;这是对问题的更详细的答复

你有什么理由不想传递 List<Part> 吗?到 View ?

您可以配置网格以隐藏 id 和 voltage 列。您可以简单地从 View 中的绑定(bind)源中获取所选对象。演示者可以查询此选择的 View ,或者 View 可以调用 SelectionChanged(Part selected)在演示者上。

这意味着您不再严格遵守 passive-view模式,而是一个 supervising controller ,因为现在您的 View 了解该模型。

如果您不喜欢这样,您可以引入一个 View 模型,您已经对 DataTable 进行了隐式处理。 (顺便说一句,这不一定是坏事。)

在您的示例中,模型类知道 View 模型,因为您在模型上有生成它们的方法。我建议您反转这种关系:在您的 View 模型上创建依赖于您的模型对象的方法。通过这种方式,您可以使您的模型类保持干净整洁,并且独立于表示层中所需的所有 UI 数据。

当使用 View 模型/监督 Controller 方式时,考虑放弃 DataTable 概念以支持简单类。

编辑:使 View 完全忽略模型的替代方法:

在演示器中构造此类的实例,其中您知道模型和 View 模型:

public class PartViewModel
{
object PartModel { get; set; }
string Name { get; set; }
string Description { get; set; }
}

传递 List<PartViewModel>作为 DataGridView 的数据源。您可以将选定的 PartViewModel 对象返回给演示者(使用事件或方法)。演示者知道它可以将 PartModel 属性转换回 Part 实例。正如您所说的那样, View 不需要了解模型的任何信息。但是您仍然可以在演示者中使用简单的对象标识,避免使用 id 的“复杂”查找。

使用演示者回调:

interface IPartListPresenter
{
// other methods
void SelectedPartChanged(PartViewModel nowSelected);
}

假设 partBindingSource 是 gridview 连接到的绑定(bind)源,您可以像这样处理 partBindingSource 的 CurrentChanged 事件:

private void partBindingSource_CurrentChanged(object sender, EventArgs e)
{
_presenter.SelectedPartChanged(partBindingSource.Current as PartViewModel);
}

在演示者中:

public void SelectedPartChanged(PartViewModel nowSelected)
{
if(nowSelected == null)
{
return;
}
part myPart = (Part) nowSelected.Part;
// dos stuff
}

希望这对您有所帮助。

关于c# - MVP 被动 View ——保持 View 数据和模型数据分离,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4386437/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com