Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/react-native/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# MVP被动视图-保持视图数据和模型数据分开_C#_Winforms_Design Patterns_Mvp_Passive View - Fatal编程技术网

C# MVP被动视图-保持视图数据和模型数据分开

C# MVP被动视图-保持视图数据和模型数据分开,c#,winforms,design-patterns,mvp,passive-view,C#,Winforms,Design Patterns,Mvp,Passive View,我使用被动视图模式实现了一个MVP三元组,即视图只包含简单的getter和setter。但是,我在分离视图数据和模型数据时遇到问题。尤其是在处理视图状态中的更改时 空间坐标轴用于使用户能够从列表中选择零件。零件列表由模型提供,每个零件由唯一id唯一标识 假设零件看起来像这样: class Part { int ID; // this code uniquely identifies the part within the model String partCode; St

我使用被动视图模式实现了一个MVP三元组,即视图只包含简单的getter和setter。但是,我在分离视图数据和模型数据时遇到问题。尤其是在处理视图状态中的更改时

空间坐标轴用于使用户能够从列表中选择零件。零件列表由模型提供,每个零件由唯一id唯一标识

假设零件看起来像这样:

class Part
{
    int ID; // this code uniquely identifies the part within the model
    String partCode;
    String description;
    double voltage;
}
private void partBindingSource_CurrentChanged(object sender, EventArgs e)
{
  _presenter.SelectedPartChanged(partBindingSource.Current as PartViewModel);
}
视图向用户显示列表,并允许用户选择零件

该列表显示在DataGridView中,并通过单击DataGridView中的行来选择零件

ID不会向用户显示,电压也不会显示,因此模型会创建一个仅包含零件代码和说明的数据表。演示者将此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;
          }
      }
}
到目前为止还不错。该视图在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;
          }
      }
}
我遇到的问题是返回用户选择的零件

视图不知道唯一ID,因为它不显示,并且无法保证其他信息是唯一的-因此无法唯一标识所选零件

本质上,我正在尝试将视图数据(选定的行)转换为模型数据(选定的零件),而没有一个组件使用其他数据

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

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

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

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,因为它是可测试的,不让逻辑进入视图,不让模型和演示者查看数据

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

该ID不会显示给用户 用户和电压都不是, 因此,该模型创建了一个 仅包含 零件代码和说明


简单的解决方案是:在datatable中创建一个ID列,我想您在这里误解了整个概念

应该由演示者来处理,而不是模型。模型应该只专注于其唯一的责任,否则,您将视图和模型保持得太近

我的建议是在表中保留一个隐藏列,并将所选行的事件传递给演示者,然后让演示者处理工作


这将是MVP的正确用法。

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

是否有不想将
列表传递给视图的原因

您可以将网格配置为隐藏id和电压列。您只需从视图中的绑定源获取所选对象。演示者可以在视图中查询此选择,或者视图可以在演示者上调用
SelectionChanged(Part selected)

这将意味着您不再严格遵循模式,而是一种模式,因为现在您的视图了解了模型

如果您不喜欢这样,可以引入一个视图模型,您已经在DataTable中隐式地这样做了。(顺便说一句,这不一定不好。)

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

使用视图模型/监视控制器的方式,考虑删除DATABATE概念,支持简单的类。 编辑:使视图完全忽略模型的替代方法:

在presenter中构造此类的实例,在该实例中,您可以同时了解模型和视图模型:

public class PartViewModel
{
  object PartModel { get; set; }
  string Name { get; set; }
  string Description { get; set; }
}
列表作为数据源传递给DataGridView。
可以将选定的PartViewModel对象返回给演示者(使用事件或方法)。演示者知道它可以将PartModel特性强制转换回零件实例。视图不需要知道关于模型的任何信息,正如您所说的您更喜欢的那样。但是您仍然可以在presenter中使用简单的对象标识,避免使用id进行“复杂”的查找

使用演示者回调:

interface IPartListPresenter
{
  // other methods
  void SelectedPartChanged(PartViewModel nowSelected);
}
假设partBindingSource是gridview连接到的bindingsource,您可以如下处理partBindingSource的CurrentChanged事件:

class Part
{
    int ID; // this code uniquely identifies the part within the model
    String partCode;
    String description;
    double voltage;
}
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
}

希望这能有所帮助。

我应该补充一点,我一直在遵循这里介绍的Presenter First方法。我不想将列表传递给视图,因为我希望视图对域对象一无所知。还因为我需要在视图中添加(未测试的)代码来格式化要显示的零件。我想尽量让视野“薄”,我明白你的意思。在这种情况下,我认为您的视图模型方法是正确的。看看我在这个答案中的建议,看看它们是否对你有用。你可能喜欢假设演示者告诉视图