开发者

Passing null child object from parent object to a partial view

开发者 https://www.devze.com 2022-12-23 01:02 出处:网络
I have an object which contains models for my ASP.NET MVC web app. The Model that is being passed into the view has sub models for \"gadgets\" o开发者_JAVA技巧n that particular view. Each of these sub

I have an object which contains models for my ASP.NET MVC web app. The Model that is being passed into the view has sub models for "gadgets" o开发者_JAVA技巧n that particular view. Each of these sub models gets passed to a partial view (gadget).

The problem is when I have a null model in the view model. See example below.

View Model:

public class FooBarHolder()
{
     public FooBar1 FooBar1 { get; set; }
     public FooBar2 FooBar2 { get; set; }
}

We pass FooBarHolder into the view and inside the view we make calls such as

<% Html.RenderPartial("Foo", Model.FooBar1); %>
<% Html.RenderPartial("Foo2", Model.FooBar2); %>

Now say for instance that Model.FooBar2 was null. What I am experiencing from the strongly typed partial view is an error that says "This view expected a model of type FooBar2 but got a model of type FooBarHolder."

Why is this happening instead of just passing in a null?


That's how the RenderPartial method works (I know should have been documented, blogged about, etc..., me too I find this a little strange). If you do not specify a model or pass null it will use the model of the parent page. To avoid this you might use the null coalescing operator:

<% Html.RenderPartial("Foo", Model.FooBar1 ?? new Foo()); %>

And if you are really curious as to how this is implemented there's an excerpt from the relevant parts of the ASP.NET MVC 2 source code:

// Renders the partial view with an empty view data and the given model
public static void RenderPartial(this HtmlHelper htmlHelper, string partialViewName, object model) {
    htmlHelper.RenderPartialInternal(partialViewName, htmlHelper.ViewData, model, htmlHelper.ViewContext.Writer, ViewEngines.Engines);
}

internal virtual void RenderPartialInternal(string partialViewName, ViewDataDictionary viewData, object model, TextWriter writer, ViewEngineCollection viewEngineCollection) {
    if (String.IsNullOrEmpty(partialViewName)) {
        throw new ArgumentException(MvcResources.Common_NullOrEmpty, "partialViewName");
    }

    ViewDataDictionary newViewData = null;

    if (model == null) {
        if (viewData == null) {
            newViewData = new ViewDataDictionary(ViewData);
        }
        else {
            newViewData = new ViewDataDictionary(viewData);
        }
    }
    else {
        if (viewData == null) {
            newViewData = new ViewDataDictionary(model);
        }
        else {
            newViewData = new ViewDataDictionary(viewData) { Model = model };
        }
    }

    ViewContext newViewContext = new ViewContext(ViewContext, ViewContext.View, newViewData, ViewContext.TempData, writer);
    IView view = FindPartialView(newViewContext, partialViewName, viewEngineCollection);
    view.Render(newViewContext, writer);
}

Notice how the case of null model is handled.


To avoid passing parent's model when child model is null, use this trick:

@Html.Partial("Child", null, new ViewDataDictionary<ChildType>(childInstance/*this can be null*/))

Credit where due...


My workaround for this strange "feature" (or bug maybe?) is:

<% Html.RenderPartial(
    "Foo2", 
    new ViewDataDictionary(ViewData) { Model = Model.FooBar2 }
); %>
0

精彩评论

暂无评论...
验证码 换一张
取 消