I am new to the whole MVP thing and slowly getting my head around it all. The a problem I am having is how to stay consistent with the MVP methodology when populating GridViews (and ddls, but we will tackle that later).
Is it okay to have it connected straight to an ObjectDataSourceID? To me this seems wrong because it bypasses all the separation of concerns MVP was made to do.
So, with that said, how do I do it? How do I handle sorting (do I send over handler events to the presentation layer, if so how does that look in code)? Right now I have a GridView that has no sorting. Code below.
ListCustomers.aspx.cs:
public partial class ListCustomers : System.Web.UI.Page, IlistCustomer
{
protected void Page_Load(object sender, EventArgs e)
{
//On every page load, create a new presenter object with
//constructor recieving the
// page's IlistCustomer view
ListUserPresenter ListUser_P = new ListUserPresenter(this);
//Call the presenter's PopulateList to bind data to gridview
ListUser_P.PopulateList();
}
GridView IlistCustomer.UserGridView
{
get { return gvUsers; }
set 开发者_JS百科{ gvUsers = value; }
}
}
Interface ( IlistCustomer.cs): is this bad sending in an entire Gridview control?
public interface IlistCustomer
{
GridView UserGridView { set; get; }
}
The Presenter (ListUserPresenter.cs):
public class ListUserPresenter
{
private IlistCustomer view_listCustomer;
private GridView gvListCustomers;
private DataTable objDT;
public ListUserPresenter( IlistCustomer view)
{
//Handle an error if an Ilistcustomer was not sent in)
if (view == null)
throw new ArgumentNullException("ListCustomer View cannot be blank");
//Set local IlistCustomer interface view
this.view_listCustomer = view;
}
public void PopulateList()
{
//Fill local Gridview with local IlistCustomer
gvListCustomers = view_listCustomer.UserGridView;
// Instantiate a new CustomerBusiness object to contact database
CustomerBusiness CustomerBiz = new CustomerBusiness();
//Call CustomerBusiness's GetListCustomers to fill DataTable object
objDT = CustomerBiz.GetListCustomers();
//Bind DataTable to gridview;
gvListCustomers.DataSource = objDT;
gvListCustomers.DataBind();
}
}
I will start by highlighting the main concerns addressed by the MVP as pattern. Firstly it is to achieve modularity through separation of concerns. This means that one can ideally change the View layer from say Web Forms to Windows forms without chnaging anything in the Presenter and Model layers. Secondly, an application designed using MVP lends itself easily to unit testing since it is very difficult to test a form. With this in mind then you realize that View-centric objects like Grid should not be manipulated in the Presenter layer since when the View changes, the controls are also likely to change. To answer your question I can approach your problem in the following manner:
// View
public interface IListCustomersView
{
public void BindGrid(IList<Customer> customers);
}
// Form e.g. Web Form, Windows Form
public class ListCustomers : IListCustomersView
{
private ListCustomersPresenter listCustomerPresenter = null;
public ListCustomers()
{
// You can use a Dependency Injector here
this.listCustomersPresenter = new ListCustomerPresenter(
new CustomerRepository(),
this);
}
public void BindGrid(IList<Customer> customers)
{
grid.DataSource = customers;
grid.Databind();
}
}
// Presenter
public class ListCustomersPresenter
{
private readonly IListCustomersView view = null;
private readonly ICustomerRespository repository = null;
public ListCustomersPresenter(
ICustomerRespository customerRepository, IListCustomersView view)
{
Guard.AgainstNull(view,"View");
Guard.AgainstNull(customerRepository,"CustomerRepository");
this.view = view;
this.customerRepository = customerRepository;
}
public void BindGrid()
{
// Fetch customers from repository
IList<Customer> customers = this.customerRepository.GetCustomers();
view.BindGrid(customers);
}
}
The convenience of using a database aware control, like Gridview, is a huge temptation. In theory one could just roll their own gridview and remain true to the MVP design. But you will be duplicating work and giving the finite resources of businesses not often the wisest choice. Since the time saving can be considerable there are compelling reason to use database aware controls.
The compromise is to clearly document via code the path in which the control connects to the database. That way if and when you migrate the UI, backend or both, you can see what is dependent on the database aware control and the backend. Also look over the database apis offered by your framework. You may have a close to generic choice that minimize problem with changing backends.
When planning your design the key question to ask is "What happens if I change the UI, the presenter, the view, the model, or database backend. The answer hopefully will lead you to a design that allows for changes.
The view interface should not expose UI components; my take would be the following
public interface IlistCustomer
{
PopulateCustomers(IEnumerable<Customer> customers);
}
public class ListUserPresenter
{
private IlistCustomer _view;
public ListUserPresenter(IlistCustomer view)
{
//Handle an error if an Ilistcustomer was not sent in)
if (view == null)
throw new ArgumentNullException("view");
_view = view;
}
public void PopulateList()
{
//Injecting your DAL seems like a good choice here
CustomerBusiness CustomerBiz = new CustomerBusiness();
IEnumerable<Customer> customers = CustomerBiz.GetListCustomers();
_view.PopulateCustomers(customers);
}
}
精彩评论