January 2008 - Posts

asp.net mvc RenderUserControl controlData

I've had a little trouble getting data from a asp.net mvc ViewPage to a ViewUserControl. The html extensions toolkit provides a RenderUserControl method that has an overload that allows for "controlData" to be explicitly sent from the ViewPage to the UserControl. I much prefere the approach of explicitly sending the required data to a user control instead of assuming that it will implicitly grab it from somewhere. I've found a few things that make this process work better for me. First, I send the data to the ViewUserControl as an anonymous type, and secondly all of my view user controls inherit from a base AppViewUserControl that I create for the application. In this base class I override a few ViewData methods to get over what looks like a bug with the current implementation of the the HTMLExtensionUtility. I was running into a problem where the "ViewData" property on the ViewUserControl should be of type object, and instead it is of type System.Web.Mvc.ViewData, and so can't be treated as an anonymous type.

So, in my base ViewUserControl class I add the following:

Partial Public Class AppViewUserControl
    Inherits System.Web.Mvc.ViewUserControl

    Private _ViewData As Object
    Protected Overrides Sub SetViewData(ByVal viewData As Object)
        MyBase.SetViewData(viewData)
        _ViewData = viewData
    End Sub

    Public Overloads ReadOnly Property ViewData() As Object
        Get
            Return _ViewData
        End Get
    End Property

End Class

There is probably a better way to do this, and this may have side effects that I haven't hit yet. But it seems to do the trick for me. Basically, all I'm doing is duplicating the storing and retrieving of the passed view data from the page to the control, so that the control's view will see the data as type object.

Once this is done, then from a mvc ViewPage, we can explicitly pass the required UserControl data as an anonymous type like this:
<%=Html.RenderUserControl("~/Views/Shared/Status.ascx",  New With {.Status = Status, .Message = Message})%>

Obviously, Status and Message are just examples in this snippet of code of data that is local to the ViewPage, and you would use your own data and properties probably from the page's local ViewData.

With this in place, then I'm able to do something like this in my ViewUserControl to use this data:
<div id="system_status"><%=ViewData.Message%></div><%=ViewData.Status%></div>

I personally like the idea of explicitly passing required data from the ViewPage to the ViewControl, similiar to how rails allows a render :partial, with a :locals symbol to tag the hash of local data for the partial.

asp.net mvc view user controls

I was having some problems getting the html helper extensions available to a custom view user controls in a asp.net mvc app. I noticed that when using the ide to "add new item" > "mvc view user control", the default behavior is to create a view with code behind. And even though the code behind class inherits from Mvc.ViewUserControl, the html helper extensions weren't available to the user control. After thinking about it for a second, I realized that I'm not planning on using code behind in my view user controls. I'm really just using these to encapsulate some common html, and any data needed will be passed as view data by the page using the control. So, I dropped the code behind and changed my @Control directive to inherit directly from System.Web.Mvc.ViewUserControl and viola, the html helper extensions were now available to the user control. Hmm. Well it works for me, I have no need for the code behind, but if I run into a situation where it becomes necessary I'll need to think about why the html extensions methods dont' appear available with the default code behind/inherit approach.