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

C# 模型视图演示者模式是否应允许WPF/Winforms中的嵌套演示者,c#,wpf,winforms,architecture,mvp,C#,Wpf,Winforms,Architecture,Mvp,最近,SO和其他人向我建议,我可以利用Model View Presenter模式重构我正在WPF和Winforms(主要是WPF)中构建的图表/流程图设计器。模型如下所示 我不明白的是,在运行时,这个模式如何与添加到设计器表面的控件一起工作。这给我提出了以下问题: public interface IDesignerView : IView { Guid Id { get; set; } Canvas Canvas { get; set; } event Even

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

我不明白的是,在运行时,这个模式如何与添加到设计器表面的控件一起工作。这给我提出了以下问题:

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)
    }
}
  • 在运行时添加到设计器中的控件/连接/覆盖/etc是否具有 拥有“演示者”,或者他们应该共享一个演示者(最有可能是设计人员演示者)
  • 如果控件/连接/覆盖/etc有自己的演示器,它们是否嵌套在DesignerPresenter中
  • 将控件添加到设计器画布时,会触发一个事件,通知演示者。设计师应该在这里参考画布吗?我不明白它为什么不能,因为我认为它负责将新组件添加到Canvas控件子元素
为此,我一直在使用一些“虚拟”演示者代码,我有以下内容:

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)
    }
}
公共接口IDesignerView:IView
{
Guid Id{get;set;}
画布画布{get;set;}
事件处理程序MouseDown;
事件处理程序控件已删除;
}
公共界面IControlView:IView
{
Guid Id{get;set;}
事件处理程序MouseDown;
}
公共类设计器视图:IDesignerView
{
公共Guid Id{get;set;}
公共画布{get;set;}
公共事件处理程序MouseDown;
公共事件事件处理程序;
}   
公共类设计器演示者:演示者
{
公共DesignerPresenter(IDesignerView视图):基础(视图)
{
}
公共覆盖无效初始化()
{
View.ControlDropped+=视图_ControlDropped;
View.MouseDown+=视图\u MouseDown;
}
私有void视图\u MouseDown(对象发送方,MouseEventArgs e)
{
//可能需要取消选择所选控件
}
私有无效视图\u控件已删除(对象发送方,鼠标目标)
{
IControlView视图=ControlBuilder.Build(…)
View.Canvas.Children.Add(视图)
}
}

几个月前我刚刚写了类似的东西。这是一个带有插件的系统,用户可以选择插件并将它们添加到画布上,然后调整大小、移动它们等等。。。我和你们之间没有像你们这样的联系,所以那个部分我不能说话

关于使用共享演示者的问题:这取决于您的场景。你需要评估它有多重。ie:内存占用、cpu资源等。您还需要考虑线程。如果多个对象需要同时更新。确定您计划支持的最大对象数,以及它对单个演示者和多个演示者的影响。(我选择了多个演示者,因为每个演示者都是自定义插件,插件的作者为其编写了视图和演示者,所以在这方面我没有太多选择。)


关于让ViewModel访问画布的问题:我不想这么说,但我确实让我的VM访问了画布。我试了一下,但就是找不到一个好的干净的方法来避免它,除非我编写自己的画布,它接受一个ItemsSource控件,该控件可以与ObservableCollection一起工作。最后,阻力最小的途径是让ViewModel访问画布。如果您的MVVM是最纯粹的,我相信这听起来很糟糕,但是替代方案太耗时了

我已经使用MVVM做了类似的事情,但您在这里使用它没有问题。不过,我对MVP的了解还不够多,还不能说

(另外,我查看了您的,但不太明白为什么您要使用MVP而不是MVVM来实现类似的功能,因为您使用的是WPF)

理想情况下,画布上的每个项目(组件、覆盖和连接器)都将由一个数据模型表示,该模型包含包含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 { ... }
在designer视图模型中,UI将绑定到这些对象的集合

public class DesignerViewModel
{
    public ObservableCollection<IDesignerComponent> Components { get; set; }
    ...
}
可以在画布上添加或拖动组件,更改其X、Y值(如果允许,还可以更改高度/宽度),并且在
OnPropertyChange
中,可以找到这些属性的任何关联组件,并更新其位置和/或大小


您的模型/视图模型根本不需要关心实际的UI组件,也不需要关心UI如何绘制它们。他们关心的只是他们之间的X、Y关系。

出于好奇,为什么在使用WPF时使用MVP而不是MVVM?