[英]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:
这为我提出了以下问题:
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
具有一个用于ItemsPanelTemplate
的Canvas
,并使用隐式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.