Model View Presenter Woes
Jumping on the bandwagon for Model View Presenter. It is something I have been intrigued with for quite awhile, but I am just getting around to implementing it.
How come almost all of the examples for MVP are the absolute most basic thing you can think of. Most of them seem to be edit pages also. I get that you put properties on your View and then set those from the Presenter, but what about list pages? Those don't seem to get enough attention.
So I set about trying to implement a list page today and I ran into a showstopping issue. I searched around and it seems like a lot of people have had this same issue, but I don't see it really being addressed in the way I am thinking.
What I am trying to do is use the ItemDataBound method of my repeater for listing out the obligatory Customer entity. Sorry, I am an unoriginal *** and I couldn't think of anything clever. So I created a view ( ICustomerListView ), a presenter ( CustomerListPresenter ) and an entity ( Customer ).
When I use declarative databinding on the repeater, this pattern works fine. Unfortunately, I am in a situation where I cannot use declarative databinding. At my new job their architecture is based around everything being in the CodeBehind and while I don't necessarily agree with it, I do understand the apprehension against it. Pretty soon you end up putting a lot of display logic into your aspx page and it can get a little messy. The problem I am running into happens in the ItemDataBound method. It acts like it cannot see the items in the repeater, which is odd, because it is firing the ItemDataBound event. It is almost like it fires the event and then loses all knowledge of having items in the repeater. Here is the code, I have tried to keep it short, maybe someone smarter than me can point out my n00bish error.
View:
namespace JeffGonzalez.SupervisingController
{
public interface ICustomerListView
{
List<Customer> Customers { set; }
}
}
Presenter:
namespace JeffGonzalez.SupervisingController
{
public class CustomerListPresenter
{
private ICustomerListView _View;
public CustomerListPresenter(ICustomerListView view)
{
_View = view;
}
public void UpdateView()
{
List<Customer> list = new List<Customer>();
list.Add(new Customer("ABC Customer"));
list.Add(new Customer("DEF Customer"));
list.Add(new Customer("GHI Customer"));
_View.Customers = list;
}
}
}
CodeBehind:
namespace JeffGonzalez.SupervisingController
{
public partial class _Default : System.Web.UI.Page, ICustomerListView
{
private CustomerListPresenter _Presenter;
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
CustomerRepeaterCodeBehind.ItemDataBound += new RepeaterItemEventHandler(CustomerRepeaterCodeBehind_ItemDataBound);
_Presenter = new CustomerListPresenter(this);
_Presenter.UpdateView();
}
void CustomerRepeaterCodeBehind_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
RepeaterItem item = e.Item;
Customer c = item.DataItem as Customer;
Label nameLabel = e.Item.FindControl("NameLabel") as Label;
nameLabel.Text = c.Name;
}
public List<Customer> Customers
{
set
{
this.CustomerRepeaterDeclarative.DataSource = value;
this.CustomerRepeaterCodeBehind.DataSource = value;
this.CustomerRepeaterDeclarative.DataBind();
this.CustomerRepeaterCodeBehind.DataBind();
}
}
}
}
For brevity I am only including the repeater with the problem, the declarative one works fine, using the <%# Eval("Name") %> syntax:
<asp:Repeater id="CustomerRepeaterCodeBehind" runat="server">
<headertemplate>
<table summary="This table displays a list of customers" width="500">
<caption>List of customers that can be individually edited</caption>
<thead>
</thead>
<tbody>
</headertemplate>
<itemtemplate>
<tr>
<td><asp:label id="NameLabel" runat="server"></asp:label></td>
</tr>
</itemtemplate>
<footertemplate>
</tbody>
</table>
</footertemplate>
</asp:Repeater>
So you can see here, I created a label called NameLabel and in the ItemDataBound method of my codebehind/View I want to get that label and set its Text property. However when I get into this method via debugging, e.Item.FindControl("NameLabel") returns null and e.Item.* returns a nullreferenceexception. I cannot get to e.Item.DataItem or anything else. I don't get it....