WinForms의 Model-View-Presenter
WinForms를 사용하여 MVP 방법을 처음으로 구현하려고합니다.
각 레이어의 기능을 이해하려고 노력하고 있습니다.
내 프로그램에는 클릭하면 openfiledialog 창을 여는 GUI 버튼이 있습니다.
따라서 MVP를 사용하여 GUI는 버튼 클릭 이벤트를 처리 한 다음 presenter.openfile ();
presenter.openfile () 내에서 해당 파일의 열기를 모델 계층에 위임해야합니까, 아니면 처리 할 데이터 나 논리가 없기 때문에 요청에 따라 작동하고 openfiledialog 창을 열어야합니까?
업데이트 : 이에 대한 추가 지원이 필요하다고 생각되는 현상금을 제공하기로 결정했으며, 상황에 맞게 아래의 특정 사항에 맞게 조정하는 것이 바람직합니다.
좋습니다. MVP를 읽은 후 Passive View를 구현하기로 결정했습니다. 실제로 나는 발표자가 처리 할 Winform에 대한 많은 컨트롤과 모델에 위임 된 작업을 갖게 될 것입니다. 내 구체적인 요점은 다음과 같습니다.
winform이로드되면 트 리뷰를 얻어야합니다. 따라서 뷰가 다음과 같은 메서드를 호출해야한다고 생각하는 것이 맞습니까? presenter.gettree (), 이것은 차례로 모델에 위임하여 트리 뷰에 대한 데이터를 가져 와서 생성하고 구성하고 발표자, 그러면 뷰로 전달되어 패널에 할당 될까요?
DataGridview도 있으므로 Winform의 모든 데이터 컨트롤에 대해 동일합니까?
내 앱에는 동일한 어셈블리를 가진 여러 모델 클래스가 있습니다. 또한 시작시로드해야하는 플러그인이있는 플러그인 아키텍처를 지원합니다. 뷰가 단순히 프레젠터 메서드를 호출하면 플러그인을로드하고 뷰에 정보를 표시하는 메서드가 호출됩니까? 그런 다음 플러그인 참조를 제어하는 계층입니다. 보기가 그들 또는 발표자에 대한 참조를 보유합니까?
뷰가 트 리뷰 노드 색상에서 데이터 그리드 크기 등에 이르기까지 프레젠테이션에 대한 모든 것을 처리해야한다고 생각하는 것이 맞습니까?
나는 그것이 나의 주요 관심사라고 생각하고 이러한 흐름이 어떻게되어야하는지 이해하면 나는 괜찮을 것이라고 생각합니다.
이것은 MVP와 특정 문제에 대한 저의 겸손한 견해입니다.
첫째 , 사용자가 상호 작용하거나 표시 할 수있는 모든 것이 뷰 입니다. 그러한 관점의 법칙, 행동 및 특성은 인터페이스에 의해 설명됩니다 . 해당 인터페이스는 WinForms UI, 콘솔 UI, 웹 UI를 사용하여 구현할 수 있으며 UI를 전혀 사용하지 않을 수도 있습니다 (일반적으로 발표자를 테스트 할 때). 구체적인 구현은 뷰 인터페이스의 법칙을 준수하는 한 중요하지 않습니다. .
둘째 ,보기는 항상 발표자가 제어합니다 . 그러한 발표자의 법칙, 행동 및 특성도 인터페이스로 설명됩니다 . 해당 인터페이스는 뷰 인터페이스의 법칙을 준수하는 한 구체적인 뷰 구현에 관심이 없습니다.
셋째 , 발표자가보기를 제어하기 때문에 종속성을 최소화하기 위해보기가 발표자에 대해 전혀 알지 못합니다. 발표자와보기간에 합의 된 계약이 있으며 이는보기 인터페이스에 의해 명시됩니다.
Third 의 의미 는 다음과 같습니다.
- 발표자는보기에서 호출 할 수있는 메서드가 없지만보기에는 발표자가 구독 할 수있는 이벤트가 있습니다.
- 발표자는 자신의 견해를 알고 있습니다. 구체적인 발표자에 생성자 주입을 사용하여이를 수행하는 것을 선호합니다.
- 보기는 어떤 발표자가 그것을 제어하고 있는지 전혀 모릅니다. 발표자에게 제공되지 않습니다.
귀하의 문제에 대해 위의 내용은 다소 단순화 된 코드로 표시 될 수 있습니다.
interface IConfigurationView
{
event EventHandler SelectConfigurationFile;
void SetConfigurationFile(string fullPath);
void Show();
}
class ConfigurationView : IConfigurationView
{
Form form;
Button selectConfigurationFileButton;
Label fullPathLabel;
public event EventHandler SelectConfigurationFile;
public ConfigurationView()
{
// UI initialization.
this.selectConfigurationFileButton.Click += delegate
{
var Handler = this.SelectConfigurationFile;
if (Handler != null)
{
Handler(this, EventArgs.Empty);
}
};
}
public void SetConfigurationFile(string fullPath)
{
this.fullPathLabel.Text = fullPath;
}
public void Show()
{
this.form.ShowDialog();
}
}
interface IConfigurationPresenter
{
void ShowView();
}
class ConfigurationPresenter : IConfigurationPresenter
{
Configuration configuration = new Configuration();
IConfigurationView view;
public ConfigurationPresenter(IConfigurationView view)
{
this.view = view;
this.view.SelectConfigurationFile += delegate
{
// The ISelectFilePresenter and ISelectFileView behaviors
// are implicit here, but in a WinForms case, a call to
// OpenFileDialog wouldn't be too far fetched...
var selectFilePresenter = Gimme.The<ISelectFilePresenter>();
selectFilePresenter.ShowView();
this.configuration.FullPath = selectFilePresenter.FullPath;
this.view.SetConfigurationFile(this.configuration.FullPath);
};
}
public void ShowView()
{
this.view.SetConfigurationFile(this.configuration.FullPath);
this.view.Show();
}
}
In addition to the above, I usually have a base IView
interface where I stash the Show()
and any owner view or view title that my views usually benefit from.
To your questions:
1. When the winform loads, it has to obtain a treeview. Am I correct in thinking that the view should therefore call a method such as: presenter.gettree(), this in turn will delegate to the model, which will obtain the data for the treeview, create it and configure it, return it to the presenter, which in turn will pass to the view which will then simply assign it to, say, a panel?
I would call
IConfigurationView.SetTreeData(...)
fromIConfigurationPresenter.ShowView()
, right before the call toIConfigurationView.Show()
2. Would this be the same for any data control on the Winform, as I also have a datagridview?
Yes, I would call
IConfigurationView.SetTableData(...)
for that. It's up to the view to format the data given to it. The presenter simply obeys the view's contract that it wants tabular data.
3. My App, has a number of model classes with the same assembly. It also supports a plugin architecture with plugins that need to be loaded at startup. Would the view simply call a presenter method, which in turn would call a method that loads the plugins and display the information in the view? Which tier would then control the plugin references. Would the view hold references to them or the presenter?
If the plugins are view-related, then the views should know about them, but not the presenter. If they are all about data and model, then the view shouldn't have anything to do with them.
4. Am I correct in thinking that the view should handle every single thing about presentation, from treeview node colour, to datagrid size, etc?
Yes. Think about it as the presenter providing XML that describes data and the view that takes the data and applies a CSS stylesheet to it. In concrete terms, the presenter might call
IRoadMapView.SetRoadCondition(RoadCondition.Slippery)
and the view then renders the road in red color.
What about data for clicked nodes?
5. If when I click on the treenodes, should I pass through the specific node to the presenter and then from that the presenter would work out what data it needs and then asks the model for that data, before presenting it back to the view?
If possible, I would pass all data needed to present the tree in a view in one shot. But if some data is too large to be passed from the beginning or if it's dynamic in its nature and needs the "latest snapshot" from the model (via the presenter), then I would add something like
event LoadNodeDetailsEventHandler LoadNodeDetails
to the view interface, so that the presenter can subscribe to it, fetch the details of the node inLoadNodeDetailsEventArgs.Node
(possibly via its ID of some kind) from the model, so that the view can update its shown node details when the event handler delegate returns. Note that async patterns of this might be needed if fetching the data might be too slow for a good user experience.
The presenter, which contains all logic in the view, should respond to the button being clicked as @JochemKempe says. In practical terms, the button click event handler calls presenter.OpenFile()
. The presenter is then able to determine what should be done.
If it decides that the user must select a file, it calls back into the view (via a view interface) and let the view, which contains all UI technicalities, display the OpenFileDialog
. This is a very important distinction in that the presenter should not be allowed to perform operations tied to the UI technology in use.
The selected file will then be returned to the presenter which continues its logic. This may involve whatever model or service should handle processing the file.
The primary reason for using an MVP pattern, imo is to separate the UI technology from the view logic. Thus the presenter orchestrates all logic while the view keeps it separated from UI logic. This has the very nice side effect of making the presenter fully unit testable.
Update: since the presenter is the embodiment of the logic found in one specific view, the view-presenter relationship is IMO a one-to-one relationship. And for all practical purposes, one view instance (say a Form) interacts with one presenter instance, and one presenter instance interacts with only one view instance.
That said, in my implementation of MVP with WinForms the presenter always interacts with the view through an interface representing the UI abilities of the view. There is no limitation on what view implements this interface, thus different "widgets" may implement the same view interface and reuse the presenter class.
The presenter should act on the request end show the openfiledialog window as you suggested. Since no data is required from the model the presenter can, and should, handle the request.
Let's assume you need the data to create some entities in your model. You can either pass the stream trough to the access layer where you have a method to create entities from the stream, but I suggest you handle the parsing of the file in your presenter and use a constructor or Create method per entity in your model.
참고URL : https://stackoverflow.com/questions/4794121/model-view-presenter-in-winforms
'developer tip' 카테고리의 다른 글
리턴을 사용할 때 스위치를 중단해야합니까? (0) | 2020.09.12 |
---|---|
C # : 정적 메서드가 여러 스레드에서 호출되면 어떻게됩니까? (0) | 2020.09.12 |
constexpr은 인라인을 의미합니까? (0) | 2020.09.12 |
http 호스트 헤더 란 무엇입니까? (0) | 2020.09.12 |
MySQL "WITH"절 (0) | 2020.09.12 |