Monday, January 07, 2008 -
This post is in response to a forum user, who is wondering how to properly use a ViewUserControl:
I'm sorry if this is a really silly question, but I'm having a hard time grokking what the right usage of a ViewUserControl looks like. Does one invoke the RenderView from a controller? If so, where is the parent page that the ViewUserControl is embedded in? Or, should you put RenderView into the ASPX of a ViewPage itself?
I can make the thing render in any number of different ways from different places, but I'm not clear on what the right MVC model is for this situation. I've read the long thread on the ".. very complex page with many MVC modules..." but I'm thinking of a simpler scenario: Let's suppose you have three or four different views that you want to compose into a page? Is this the right scenario for a ViewUserControl? If so, where would you reference the control itself?
This is an interesting issue, and as he went on to point out, there are lots of ways to use these partial UI bits to your advantage. As always, I'll offer some ideas here for you, but this is not the only way to do it.
The "Viewlet"
Given that a ViewPage inherits from System.Web.Page, you can still register and reference a UserControl (.ascx file) on a View and have it render. You can even pass it data in the code behind or as a property setting:
<uc1:MyUserControl ID=myControlView runat=server myProperty="Hi Mom" />
But using the WebForms model inside MVC can be a little confusing - especially for folks who will pick up your project later. In this case - the ViewUserControl will render just fine, and in many cases it's all you need. But if you're interesting in keeping things as modular as possible within MVC, read on.
Your UseControl can be one of two things:
The idea here is reusability and maintainability.
I personally don't like the idea of putting logic into ViewUserControls, but at the same time it can serve a purpose - with portal stats for instance where you might want to serve up personalized links (using the Memebership.Profile for instance), etc.
In other MVC frameworks they make a distinction between the two. In Rails, for instance, a "Partial" is simply a View that's shared between views, and not meant to be standalone. If you've ever used Rails to create the demo scaffold, you've used the partial "_form.rhtml" which is responsible for rendering an input form for the New and Edit views.
If you need more than basic rendering of HTML in Rails, you can move to a Layout. Layouts essentially wrap UI around some logic, and are a nice modular way to reuse UI/logic elements around an application. These are like "UserControls Light".
Rails also allows for "sub apps" called "Components", which are useful when you have "sub applications" like an image gallery or rss reader. The idea here is that these components contain their own logic and can be used between many applications.
My point with all this is that if you feel lost trying to make a decision (architecturally) regarding MVC - it helps to see how other platforms do it (like Rails or Django).
Rendering a ViewUserControl
The MVC Toolkit has a nice method called "RenderUserControl()" that allows you to process your ViewUserControl and output it's result inline:
<%=Html.RenderUserControl("~/UserControls/UserList.ascx")%>
If the ViewUserControl is typed (say ViewUserControl<MyControllerData>), then it's ViewData object will be filled for you, and your ViewPage and rendered control will share the same data.
If you want to be explicit about it, you can do that as well, specifying the data to pass:
<%=Html.RenderUserControl("~/UserControls/UserList.ascx",ViewData.Users)%>
Finally, if you need to set properties on the ViewUserControl, you can do that as well by passing in an anonymous type:
<%=Html.RenderUserControl("~/UserControls/UserList.ascx",ViewData.Users, new {GroupID=2})%>
Using the RenderUserControl method allows you to have complete control over how your ViewUserControl is supposed to be used
Summary
UserControls are a great way (still) to encapsulate UI elements for your MVC app. There are many ways to use them, and if you have one I didn't mention (or dislike my approach here) - do let me know. As always - we're still CTP and there's lots of room for comments.
It's really a matter of semantics, because you could create a WidgetController, just don't descend it from the base Controller, and expose a Show() method that grabs the needed data as well as either hand generates the HTML or instead makes the call to RenderView itself. The only real downside I see to this approach though is maintainability in teams. Now you have two types of controllers and you need to let others know at a glance that it's not a main controller. I believe some people get around this by instead calling them Services :)
I hope the MVC team keeps that in mind as well, that we don't need a 100 different methods to do the same thing because with extensions and 3.5 it's much easier to extend the framework on our own, keeping MVC a clean framework to build up from instead of an all encompassing beast like WebForms.
sorry for wrong article to ask, but I have one question on MVC databinding (and UpdateFrom method). Suppose I have control. UpdateFrom method will unbind control's value to my object's Name property (if one exists). Does unbinding using id or name attribute for Property name and can I use different id and name values, for example id="txtName" and name="Name". If so, are you going to implement this kind of overload to HtmlHelper extension method Text()?
I suppose i'm begging for some sample c# solutions that have a simple example of a few pages with an MVC View User Control being used in each one ... AND ... the MVC VUC having a simple 'postback' ... say a linkbutton (the equiv, if we were using the asp.net webforms stuff .. which we are not). In the code i'm trying to do, i'm trying to drop a reusable control onto various Views which toggles something in the user's Session -- for example .. maybe .. times in 24hour or 12 hour.
Once i've got this working, i was going to try and AJAX that MVC VUC ... but that's a whole other huge problem. Sounds like i'm going to look at JQuery or Prototype ... which is another new learning experience because i'm used to some simple MS Ajax stuff (eg. UpdatePanel).
So much to learn and so little time.
Would love some suggestions / help :)