I have a WinForms application setup to use Model View Presenter. To avoid the view from knowing about the model, I am considering having my presenter use an instance of the view to access the view textboxes and databind them to an instance of the model the presenter also has. What problems are there in taking this approach?
The other option I have considered is having the view have an instance of the model. The model properties would have INotifyPropertyChanged setup. In this case, I could have the view setup the databinding to the textboxes it has to the model instance it also has. What problems are there in doing it this way?
Another option I have considered is to replicate the model properties into the presenter and set them up with INotifyPropertyChanged. Then with the view having an instance of the presenter, I could have the view databind its textboxes to the matching properties in the presenter. With this setup, when the presenter makes data access calls it would set values to the properties in itself which would automatically update the view textboxes which are databound to the presenter properties.
If I were not using databinding I would just add getters and setters in the view for the presenter to access the view textbox values. The presenter would use the view getters and setters to carry out calls for data access. The presenter would also use the setters to set the view textbox values after receiving data from data access calls.
These options I am considering are based on articles I've seen but perhaps there is another way to manage the data in a WinForms MVP implementation I have not seen. Please provide feedback on what the recommended approach is for managing data back and forth from the view to either the presenter or model or perhaps there is another layer to be added here like some kind of service? Thanks in advance.
================================= Update 04/10/2018
I was able to setup my application so the View and Model have no references to the Presenter while allowing the Presenter to have references to the View and Model. This became possible as I found out how to bind to data the View needed for its controls from within the Presenter. This negates the need to have the Presenter directly access the visual controls that belong to the View.
DepartmentPresenter fields:
public class DepartmentPresenter : IDepartmentPresenter
{
private IDepartmentView departmentView;
private IDepartmentModel departmentModel;
private IDepartmentRepository departmentRepository;
....
}
Here is the instantiation for the Presenter:
void OnDisplayDepartmenSelectedRaised(object sender, DisplayDepartmentSelectedEventArgs e)
{
//Get current selected data row from Presenters BindingSource which used by the View to bind
//to its DataGridView. The view only knew it wasw a BindingSource and never had to know it
//was a collectino of DepartmentModel Data Transfer Objects (DTOs)
selectedDepartmentModel = (DepartmentModel)departmentModelBindingSource.Current;
DepartmentPresenter aDepartmentPresenter = new DepartmentPresenter(departmentView,
departmentRepository,
selectedDepartmentModel.DepartmentId);
}
The Presenter constructor:
public DepartmentPresenter(IDepartmentView departmentView,
IDepartmentRepository departmentRepository,
int selectedDepartmentId)
{
this.departmentRepository = departmentRepository;
departmentModel = departmentRepository.GetById(selectedDepartmentId);
this.departmentView = departmentView;
//Subscribe to View's save request from save button so Presenter can perform work to be done on a save
this.departmentView.SaveDepartmentRaised += new EventHandler(OnSaveDepartmentRaised);
//Create bindings for data the View will use on its textBoxes
Binding departmentNameBinding = new Binding("Text", DepartmentModel, "DepartmentName", true, DataSourceUpdateMode.OnPropertyChanged);
Binding cityLocationBinding = new Binding("Text", departmentModel, "CityLocation", true, DataSourceUpdateMode.OnPropertyChanged);
Binding stateLocationBinding = new Binding("Text", departmentModel, "StateLocation", true, DataSourceUpdateMode.OnPropertyChanged);
//Store bindings into a dictionary for the View to access for its textBoxes
Dictionary<string, Binding> bindingDictionary = new Dictionary<string, Binding>();
bindingDictionary.Add("DepartmentName", departmentNameBinding);
bindingDictionary.Add("CityLocation", cityLocationBinding);
bindingDictionary.Add("StateLocation", stateLocationBinding);
//Use passed in reference to View to tell view to bind its textBoxes using the passed in Dictionary of bindings
this.departmentView.BindDisplayData(bindingDictionary);
this.departmentView.ShowView();
}
Here is how the View binds to its textBox controls in response to the Presenter telling it to do so:
public void BindDisplayData(Dictionary<string, Binding> bindingDictinary)
{
textBoxName.DataBindings.Add(bindingDictinary["DepartmentName"]);
textBoxCity.DataBindings.Add(bindingDictinary["CityLocation"]);
textBoxState.DataBindings.Add(bindingDictinary["StateLocation"]);
}
Here is the interface definition for the View:
public interface IDepartmentView
{
event EventHandler SaveDepartmentRaised;
void ShowView();
void BindDisplayData(Dictionary<string, Binding> bindingDictinary);
}
Hopefully this will help someone trying to bind to a view from a presenter in an Model View Presenter project while trying to avoid making the View have an instance of the Presenter.