简体   繁体   English

模型视图演示者模式是否应允许WPF / Winforms中的嵌套演示者

[英]Should Model-View-Presenter Pattern Allow for Nested Presenters in WPF/Winforms

It was recently suggested to me on SO and by others that I could utilize the Model-View-Presenter pattern to refactor a diagram/flowchart designer I am building in WPF and Winforms (mostly WPF).The mockup is shown below. 最近有人在SO和其他工具上向我建议,我可以利用Model-View-Presenter模式来重构我在WPF和Winforms(主要是WPF)中构建的图/流程图设计器。模型如下所示。

在此处输入图片说明

What I do not understand is how this pattern would work with controls being added to the designer surface at runtime. 我不明白的是,这种模式如何与在运行时将控件添加到设计器图面中一起使用。 The questions this raises for me is the following: 这为我提出了以下问题:

  • Do the Controls/Connections/Overlays/etc that are added to the designer at run time have their own 'Presenter' or should they share a presenter (most likely the DesignerPresenter). 在运行时添加到设计器中的Controls / Connections / Overlays / etc是否具有自己的“ Presenter”,或者应该共享演示者(很可能是DesignerPresenter)。
  • If the Controls/Connections/Overlays/etc have their own presenter, are they nested in the DesignerPresenter? 如果Controls / Connections / Overlays / etc具有自己的演示者,它们是否嵌套在DesignerPresenter中?
  • When a Control is added to the Designer Canvas, I have an event triggered notifying the presenter. 将控件添加到Designer画布后,我触发了一个事件来通知演示者。 Should the designer have reference to the canvas here? 设计师应该在这里引用画布吗? I dont see how it could not since I would imagine it is responsible for adding the new component to the Canvas Control Childen. 我看不到它为什么不能,因为我以为它负责将新组件添加到Canvas Control Childen中。

I have been playing around with some 'dummy' presenter code for this and I have the following: 我一直在为此使用一些“虚拟”演示者代码,并且具有以下内容:

public interface IDesignerView : IView
{
    Guid Id { get; set; }

    Canvas Canvas { get; set; }

    event EventHandler<MouseEventArgs> MouseDown;
    event EventHandler<MouseEventArgs> ControlDropped;
}

public interface IControlView : IView
{
    Guid Id { get; set; }

    event EventHandler<MouseEventArgs> MouseDown;
}

public class DesignerView : IDesignerView
{
    public Guid Id { get; set; }
    public Canvas Canvas { get; set; }

    public event EventHandler<MouseEventArgs> MouseDown;
    public event EventHandler<MouseEventArgs> ControlDropped;
}   

public class DesignerPresenter :Presenter<IDesignerView>
{
    public DesignerPresenter(IDesignerView view) : base(view)
    {

    }

    public override void Initialize()
    {
        View.ControlDropped += View_ControlDropped;
        View.MouseDown += View_MouseDown;

    }

    private void View_MouseDown(object sender, MouseEventArgs e)
    {
        //Might need to unselect selected controls
    }

    private void View_ControlDropped(object sender, MouseEventArgs e)
    {
        IControlView view = ControlBuilder.Build(...)
        View.Canvas.Children.Add(view)
    }
}

I've done something similar using MVVM and don't see a problem with you using it here. 我使用MVVM做过类似的事情,在这里使用它看不到问题。 I don't know enough about MVP to speak about it though. 我对MVP的了解还不够,无法谈论它。

(Also, I looked at your other question , and don't really see why you'd want to use MVP over MVVM for something like this since you're working with WPF) (此外,我查看了您的其他问题 ,但由于您使用的是WPF,因此并没有真正看到您为什么要在MVVM上使用MVP这样的功能)

Ideally each item on your canvas (Components, Overlays, and Connectors) would be represented by a data model that includes attributes containing the size and position of the boejct 理想情况下,画布上的每个项目(“组件”,“覆盖”和“连接器”)都将由一个数据模型来表示,该数据模型应包含属性,该属性包含对象的大小和位置

public interface IDesignerComponent
{
    int X { get; set; }
    int Y { get; set; }
    int Height { get; set; }
    int Width { get; set; }
}

public class ComponentModel : IDesignerComponent { ... }
public class ConnectorModel: IDesignerComponent { ... }
public class OverlayModel: IDesignerComponent { ... }

And you'd have a collection of these objects for the UI to bind to in your designer view model 您将拥有这些对象的集合以供UI绑定到设计器视图模型中

public class DesignerViewModel
{
    public ObservableCollection<IDesignerComponent> Components { get; set; }
    ...
}

I would then draw this collection using an ItemsControl that has a Canvas for an ItemsPanelTemplate , and that uses implicit DataTemplates to define how each item gets drawn. 然后,我将使用ItemsControl绘制此集合,该ItemsControl具有一个用于ItemsPanelTemplateCanvas ,并使用隐式DataTemplates定义如何绘制每个项目。

<ItemsControl ItemsSource="{Binding Components}">

    <!-- // DataTemplates for all 3 types of objects -->
    <ItemsControl.Resources>
        <DataTemplate DataType="{x:Type local:ComponentModel}">
            <local:MyComponentControl 
                Height="{Binding Height}" 
                Width="{Binding Width}" />
        </DataTemplate>
        <DataTemplate DataType="{x:Type local:ConnectorModel}">
            <local:MyConnectorControl 
                Height="{Binding Height}" 
                Width="{Binding Width}" />
        </DataTemplate>
        <DataTemplate DataType="{x:Type local:OverlayModel}">
            <local:MyOverlayControl 
                Height="{Binding Height}" 
                Width="{Binding Width}" />
        </DataTemplate>
    </ItemsControl.Resources>

    <!-- // ItemsPanelTemplate - May need to set or bind Canvas Height/Width too-->
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>

    <!-- // ItemContainerStyle - Sets x,y position of items -->
    <ItemsControl.ItemContainerStyle>
        <Style>
            <Setter Property="Canvas.Left" Value="{Binding X}" />
            <Setter Property="Canvas.Top" Value="{Binding Y}" />
        </Style>
    </ItemsControl.ItemContainerStyle>
</ItemsControl>

Components can be Added or Dragged around on the Canvas, changing their X,Y values (and possibly Height/Width if you allow it), and in the OnPropertyChange for these properties you can find any associated components and update their position and/or size as well. 可以在画布上添加或拖动组件,更改其X,Y值(如果允许,还可以更改其高度/宽度),在这些属性的OnPropertyChange ,您可以找到任何关联的组件并更新其位置和/或大小也一样

Your Models/ViewModels don't need to care about the actual UI components at all, or how they get drawn by the UI. 您的Models / ViewModels根本不需要关心实际的UI组件,也不用担心它们如何被UI绘制。 All they care about is their X,Y relation to each other. 他们只关心彼此的X,Y关系。

I just wrote something similar to this a few months ago. 我几个月前刚刚写了类似的东西。 It was system with Plugins and a user could select plugins and add them to a Canvas, then resize, move them etc... I didn't have connections between them like yours has, so that part I cannot speak to. 它是带有插件的系统,用户可以选择插件并将其添加到“画布”,然后调整大小,移动它们等...我之间没有像您一样的连接,因此我无法与之交谈。

On the question of using a shared presenter or one each: it really depends on your scenario. 关于使用共享演示者还是每个演示者的问题:这实际上取决于您的方案。 You need to assess how "heavy" it is. 您需要评估它的“重量”。 ie: memory footprint, cpu resources etc. Also you need to take into consideration threading. 即:内存占用量,CPU资源等。另外,您还需要考虑线程。 If multiple objects need to update at the same time. 如果多个对象需要同时更新。 Determine how many the max number of objects you plan to support is, and what it would do to single vs multiple presenters. 确定您计划支持的最大对象数是多少,以及对单个或多个演示者的处理方式。 (I went with multiple presenters as each one was a custom plugin and the author of the plugin wrote the view and presenter for it, so I didn't have much choice in this regard.) (我和多个演示者一起去了,因为每个演示者都是一个自定义插件,并且插件的作者为此编写了视图和演示者,所以在这方面我没有太多选择。)

On the question of letting the ViewModel have access to the Canvas: I hate to say it but I did let my VM have access to the Canvas. 关于让ViewModel可以访问Canvas的问题:我不想这么说,但是我确实让我的VM可以访问Canvas。 I tried for a bit, but just couldn't find a nice clean way to avoid it unless I wrote my own Canvas that accepted an ItemsSource of controls that would work with an ObservableCollection. 我尝试了一下,但是除非我编写自己的Canvas接受可以与ObservableCollection一起使用的控件的ItemsSource,否则找不到避免它的好方法。 In the end the path of least resistance was letting the ViewModel have access to the Canvas. 最后,阻力最小的路径是让ViewModel可以访问Canvas。 If your a MVVM purest I'm sure that sounds awful, but the alternative was too time consuming. 如果您的MVVM最纯净,我相信这听起来很糟糕,但是替代方法却很费时。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 WinForms中的模型视图呈现器 - Model-View-Presenter in WinForms WinForms中的RX和Model-View-Presenter - RX and Model-View-Presenter in WinForms Model-View-Presenter模式中的Presenter是否应该在视图上处理多个“ UI”元素? - Should a Presenter in the Model-View-Presenter pattern handle multiple 'UI' elements on a View? 使用StructureMap在模型 - 视图 - 展示器模式中进行Presenter注入 - Presenter injection in Model-View-Presenter pattern with StructureMap 带有代表,活动和嵌套演示者的模型视图演示者 - Model-View-Presenter with Delegates, Events and Nested Presenter C#WinForms模型 - 视图 - 演示者(被动视图) - C# WinForms Model-View-Presenter (Passive View) 模型 - 视图 - 展示器模式中“视图”的目的是什么? - What is the purpose of the “View” in the Model-View-Presenter pattern? 关于模型 - 视图 - 演示者(C#)的一般性问题,模型应该知道演示者吗? - A general question on model-view-presenter (C#), should the model know the presenter? 如何构造C#WinForms模型视图呈现器(被动视图)程序? - How to Structure a C# WinForms Model-View-Presenter (Passive View) Program? 在Model-View-Presenter中使用DataGridView - Using DataGridView in Model-View-Presenter
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM