繁体   English   中英

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

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

最近有人在SO和其他工具上向我建议,我可以利用Model-View-Presenter模式来重构我在WPF和Winforms(主要是WPF)中构建的图/流程图设计器。模型如下所示。

在此处输入图片说明

我不明白的是,这种模式如何与在运行时将控件添加到设计器图面中一起使用。 这为我提出了以下问题:

  • 在运行时添加到设计器中的Controls / Connections / Overlays / etc是否具有自己的“ Presenter”,或者应该共享演示者(很可能是DesignerPresenter)。
  • 如果Controls / Connections / Overlays / etc具有自己的演示者,它们是否嵌套在DesignerPresenter中?
  • 将控件添加到Designer画布后,我触发了一个事件来通知演示者。 设计师应该在这里引用画布吗? 我看不到它为什么不能,因为我以为它负责将新组件添加到Canvas Control Childen中。

我一直在为此使用一些“虚拟”演示者代码,并且具有以下内容:

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)
    }
}

我使用MVVM做过类似的事情,在这里使用它看不到问题。 我对MVP的了解还不够,无法谈论它。

(此外,我查看了您的其他问题 ,但由于您使用的是WPF,因此并没有真正看到您为什么要在MVVM上使用MVP这样的功能)

理想情况下,画布上的每个项目(“组件”,“覆盖”和“连接器”)都将由一个数据模型来表示,该数据模型应包含属性,该属性包含对象的大小和位置

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 { ... }

您将拥有这些对象的集合以供UI绑定到设计器视图模型中

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

然后,我将使用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>

可以在画布上添加或拖动组件,更改其X,Y值(如果允许,还可以更改其高度/宽度),在这些属性的OnPropertyChange ,您可以找到任何关联的组件并更新其位置和/或大小也一样

您的Models / ViewModels根本不需要关心实际的UI组件,也不用担心它们如何被UI绘制。 他们只关心彼此的X,Y关系。

我几个月前刚刚写了类似的东西。 它是带有插件的系统,用户可以选择插件并将其添加到“画布”,然后调整大小,移动它们等...我之间没有像您一样的连接,因此我无法与之交谈。

关于使用共享演示者还是每个演示者的问题:这实际上取决于您的方案。 您需要评估它的“重量”。 即:内存占用量,CPU资源等。另外,您还需要考虑线程。 如果多个对象需要同时更新。 确定您计划支持的最大对象数是多少,以及对单个或多个演示者的处理方式。 (我和多个演示者一起去了,因为每个演示者都是一个自定义插件,并且插件的作者为此编写了视图和演示者,所以在这方面我没有太多选择。)

关于让ViewModel可以访问Canvas的问题:我不想这么说,但是我确实让我的VM可以访问Canvas。 我尝试了一下,但是除非我编写自己的Canvas接受可以与ObservableCollection一起使用的控件的ItemsSource,否则找不到避免它的好方法。 最后,阻力最小的路径是让ViewModel可以访问Canvas。 如果您的MVVM最纯净,我相信这听起来很糟糕,但是替代方法却很费时。

暂无
暂无

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM