我应该通过绑定使用 MVP 和 WPF 显示数据吗?

Should I display data using MVP and WPF through binding?

我正在写一篇关于代码设计的论文,我正在比较 MV-C、P 和 VM,看看哪一个最适合 WPF。在我的研究过程中,我意识到 MVVM 是其他标准中数据绑定的明显选择原因。

即使我知道这一点,在某种意义上我也必须"prove",所以我在 MVP 和 MVVM 中创建了一个应用程序,它做的事情完全相同,但处理代码的方式不同。有了这个,我将解释这些代码模式的优缺点,但在我使用 MVP 应用程序创建时遇到了问题。

我有一个带有 "buisness-logic" 的模型,我的演示者创建了我的视图可以显示的这些模型对象的列表。

我的问题是如何显示它们

在 MVVM 中,我将我的列表绑定到 ListBox 因为这就是 MVVM "made" 的工作方式。 EG

<Window.Resources>
  <DataTemplate DataType="{x:type model:Mymodel}">
    //Some DataTemplate Definition
  </DataTemplate>
</Window.Resources>

然后绑定到我的Listbox

<ListBox ItemSources={Binding someProperty} />

它没有完全编码,但你得到了手势

但如果我理解正确的话,绑定 与 MVP 不应该是这样的。

你不应该在 MVP 中绑定任何东西,因为这不是它应该如何工作的,或者我在这里错了吗?

因此,如果我不应该绑定数据,我该如何在 ListBox 中显示我的模型对象列表,这样它就不会说

Model Object
Model Object
Model Object
Model Object

我知道您应该为 WPF 使用 MVVM,但为了证明为什么它更好,我需要展示 MVP 如何在 WPF 中工作。

我无法在评论中添加尽可能多的代码,所以我会 post 一个答案。如果有什么不清楚的地方,请给我反馈,我会为您提供更多详细信息。

根据您展示的示例,我将着手进行从 ViewPresenter 的绑定,这应该是[之间的桥梁] =34=]View 和 Model 如您所见:

(图片来自wikipedia article

View 应该发送 events/changes 给演示者,演示者应该是 View 的 "brain/logic"决定是否应该更新 Model


假设您的 View 像这样:

<UserControl x:Class="EntryNamespace.MeView"
    ... >

    <!-- ListItems should return collection of Presenters -->
    <ListView ItemsSource="{Binding ListItems, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
        <ListView.ItemTemplate>
            <DataTemplate>
                <!-- Elementcontent should be a property inside Presenter that returns value from Model -->
                <Button Content="{Binding ElementContent}"/>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

</UserControl>

您可以像这样创建一个 Presenter :

class Presenter : INotifyPropertyChanged
{
    public ObservableCollection<ListItemPresenter> ListItems
    {
        get { return GetItems(); }
        set { SetItems(value); }
    }

    ObservableCollection<ListItemPresenter> GetItems()
    {
        // private logic to retrieve `ListItemPresenter` collection from model

        var collection = new ObservableCollection<ListItemPresenter>();
        foreach(ListItem listItem in Model.Items)
            collection.Add(listItem.GetPresenter());

        return collection;
    }

    void SetItems(ObservableCollection<ListItemPresenter> objects)
    {
        // private logic to transfer `ListItemPresenter` collection to model
        // remember to call NotifyPropertyChanged("ListItems");

        Model.Items.Clear();
        foreach(ListItemPresenter presenter in objects)
            Model.Items.Add(presenter.GetModel());

        NotifyPropertyChanged("ListItems");
    }
}

你的模特可以看起来像这样:

public class ListItem
{
    ListItemPresenter m_Presenter;

    public ListItemPresenter GetPresenter()
    {
        return m_Presenter;
    }

    string m_ElementContent;

    public string ElementContent
    {
        get { return m_ElementContent; }
        set { m_ElementContent = value; }
    }

    public ListItem(ListItemPresenter presenter)
    {
        m_Presenter = presenter;
    }
}

使用 Presenter 的另一种方法可能如下所示:

假设您有类似的 View 只需创建一个 Presenter:

public class Presenter
{
    ObservableCollection<ListItem> m_ListItems = new ObservableCollection<ListItem>(); 

    public ObservableCollection<List> ListItems
    {
        get { return m_ListItems; }
    }

    public Presenter(MeView view)
    { 
        Binding binding = new Binding("ListItems");
        binding.Source = ListItems;
        view.MeListView.SetBinding(ListView.ItemsSourceProperty, binding);
        // other view events, bindings etc.
    }
}

这不是 ViewModel 之间间接通信的最佳方式,但应该给你一些小提示。如果您想拆分控件,让每个控件都有自己的 Presenter,或者您想要每个 window.

一个,则由您决定

当您使用 WPF 时,正如您所说,它是通过数据绑定与 MVVM 一起工作的。 MVP 通常与 Windows-form 一起使用,其中没有可用的数据绑定。如果您希望您的应用程序具有相同的功能并使用相同的技术 (WPF),则无法避免使用绑定,或者至少更难做到。只要您通过演示者与您的模型交谈,您仍在使用 MVP。你可以自己决定是否要使用

  • 被动视图 - 演示者处理视图和模型之间的所有对话
  • SuperVising Presenter - View 了解模型,而 Presenter 处理 "difficult-code" 在视图和模型之间需要处理的事情太多了。

如果您正在使用绑定,我会说(不确定)您正在使用 SuperVising Presenter 而不是 "recommended",但是在 WPF 中使用 MVP 是也不推荐所以...

编辑示例

例如,如果你想显示一个列表,你需要一个界面,该界面有一个 属性 包含你要显示的对象的列表。

public interface myinterface
{
  ObservableCollection<YourModel> ListName {get; set;}
}

然后在您的演示者中 "push" 该列表的数据

private myinterface _my;
public Presenter(myinterface my)
{ this._my = my;}

_my.ListName = // Add whatever Data you want into this list.

在你看来

<ListBox ItemSource ={Binding ListName}>
  <ListBox.ItemTemplate>Set how you want to display the list</ListBox.ItemTemplate>

这是一个不清楚的示例,但希望可以让您了解 MVP 如何与 WPF 一起工作(以一种小的方式)