问题
I have a page:
<%@ Page Inherits=\"System.Web.Mvc.View<DTOSearchResults>\" %>
And on it, the following:
<% Html.RenderPartial(\"TaskList\", Model.Tasks); %>
Here is the DTO object:
public class DTOSearchResults
{
public string SearchTerm { get; set; }
public IEnumerable<Task> Tasks { get; set; }
and here is the partial:
<%@ Control Language=\"C#\" Inherits=\"System.Web.Mvc.ViewUserControl<IEnumerable<Task>>\" %>
When Model.Tasks is not null, everything works fine. However when its null I get:
The model item passed into the dictionary is of type \'DTOSearchResults\' but this dictionary requires a model item of type \'System.Collections.Generic.IEnumerable`1[Task]\'.
I figured it must not know which overload to use, so I did this (see below) to be explicit, but I still get the same issue!
<% Html.RenderPartial(\"TaskList\", (object)Model.Tasks, null); %>
I know I can work around this by checking for null, or not even passing null, but that\'s not the point. Why is this happening?
回答1:
Andrew I think the problem you are getting is a result of the RenderPartial method using the calling (view)'s model to the partial view when the model you pass is null.. you can get around this odd behavior by doing:
<% Html.RenderPartial("TaskList", Model.Tasks, new ViewDataDictionary()); %>
Does that help?
回答2:
@myandmycode's answer is good, but a slightly shorter one would be
<% Html.RenderPartial("TaskList", new ViewDataDictionary(Model.Tasks)); %>
This works because the ViewDataDictionary
is the thing that holds the model, and it can accept a model as a constructor parameter. This basically passes an "entire" view data dictionary, which of course only contains the possibly-null model.
回答3:
It appears that when the property of the Model you're passing in is null MVC intentionally reverts back to the "parent" Model. Apparently the MVC engine interprets a null model value as intent to use the previous one.
Slightly more details here: ASP.NET MVC, strongly typed views, partial view parameters glitch
回答4:
If you do not want to loose your previous ViewData in the partial view, you could try:
<% Html.RenderPartial("TaskList", Model.Tasks, new ViewDataDictionary(ViewData){Model = null});%>
回答5:
A solution would be to create a HtmlHelper like this:
public static MvcHtmlString Partial<T>(this HtmlHelper htmlHelper, string partialViewName, T model)
{
ViewDataDictionary viewData = new ViewDataDictionary(htmlHelper.ViewData)
{
Model = model
};
return PartialExtensions.Partial(htmlHelper, partialViewName, model, viewData);
}
The Partial<T>(...)
matched before the Partial(...)
so convenient and no ambiguity error when compiling.
Personally I find it difficult to understand the behaviour - seems hard to imagine this as design choice?
回答6:
Though this has been answered, I ran across this and decided I wanted to solve this issue for my project instead of working around it with new ViewDataDictionary()
.
I created a set of extension methods:
https://github.com/q42jaap/PartialMagic.Mvc/blob/master/PartialMagic.Mvc/PartialExtensions.cs
I also added some methods that don't call the partial if the model is null, this will save a lot of if statements.
I created them for Razor, but a couple of them should also work with aspx style views (the ones that use HelperResult probably aren't compatible).
The extension methods look like this:
@* calls the partial with Model = null *@
@Html.PartialOrNull("PartialName", null)
@* does not call the partial if the model is null *@
@Html.PartialOrDiscard("PartialName", null)
There are also methods for IEnumerable<object>
models and the discard ones can also be called with a Razor lambda that allow you to wrap the partial result with some html.
Feel free to use them if you like.
回答7:
My workaround to this is:
<% Html.RenderPartial("TaskList", Model.Tasks ?? new List()); %>
来源:https://stackoverflow.com/questions/650393/renderpartial-with-null-model-gets-passed-the-wrong-type