2010-03-17 22 views
6

Tengo un objeto que contiene modelos para mi aplicación web ASP.NET MVC. El modelo que se pasa a la vista tiene submodelos para "gadgets" en esa vista particular. Cada uno de estos submodelos pasa a una vista parcial (gadget).Pasando nulo objeto hijo desde el objeto principal a una vista parcial

El problema es cuando tengo un modelo nulo en el modelo de vista. Vea el ejemplo a continuación.

Ver Modelo:

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

Nos pasan FooBarHolder en la vista y dentro del punto de vista que hacen llamadas como

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

ahora dicen por ejemplo que Model.FooBar2 era nula. Lo que estoy experimentando de la vista parcial fuertemente tipada es un error que dice "Esta vista esperaba un modelo de tipo FooBar2 pero obtuvo un modelo de tipo FooBarHolder".

¿Por qué sucede esto en lugar de pasar en un nulo?

Respuesta

7

Así es como funciona el método RenderPartial (sé que debería haber sido documentado, publicado en el blog, etc., a mí también, esto me parece un poco extraño). Si no especifica un modelo o pasa null, usará el modelo de la página principal. Para evitar esto se puede utilizar el operador nula coalescencia:

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

Y si usted es realmente curioso en cuanto a cómo se implementa esto no es un extracto de las partes pertinentes del código fuente de ASP.NET MVC 2:

// 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); 
} 

Observe cómo se maneja el caso del modelo nulo.

+0

gracias por esta clara explicación, ¡habría estado trabado durante horas si no fuera por usted! En tu caso creas un nuevo Foo() difícil, ¿y si realmente QUIERES pasar el nulo allí? –

1

Mi solución para esta "característica" extraña (o error, tal vez?) Es:

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

Has probado esto? No funciona para vistas fuertemente tipadas aquí ... –

2

Para evitar que pase el modelo de los padres cuando niño modelo es nulo, utilice este truco:

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

Credit where due...

Cuestiones relacionadas