MsCorEE

JeffGonzalez : IScalable

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....
 

Comments

JAlexandrian said:

You need to hook up the ItemDataBound event on Init instead of on Load. Move CustomerRepeaterCodeBehind.ItemDataBound += new RepeaterItemEventHandler(CustomerRepeaterCodeBehind_ItemDataBound); to the OnInit() override and it will work for you.

# March 7, 2007 10:14 PM

likwid said:

I actually tried it both ways.  Neither of them work.  I started with OnInit.

# March 8, 2007 12:07 AM

likwid said:

Man I feel like a grade A moron.  I write this code every day and I left it out.

Thanks to joe, iom and garry for politely pointing out my ignorance!

# March 8, 2007 9:03 PM

LarryB said:

Eh?  Did I miss some posts, or were the solutions not posted?

# March 9, 2007 9:01 AM

Jeff Gonzalez said:

I forgot to put them in.  I updated the other post.

You can find it here:

http://weblogs.asp.net/jgonzalez/archive/2007/03/08/model-view-presenter-redemption.aspx

# March 9, 2007 12:29 PM

mvp boy said:

The real struggle you having is that databinding breaks the mvp model.  Think about it for a second.  You are moving model logic directly on the view and letting the view decide how it interacts with model objects (which is the point of a presenter).  MVP, is pattern that is language agnostic, in that most languages dont have MS's (RAD centric databinding madness).  So if you want to be pure MVP, and take advantage of a true sepration of concerns, you have to gut your application of its databinding all together.

# October 29, 2008 2:22 PM
Leave a Comment

(required) 

(required) 

(optional)

(required)