16

I created following custom ActionResult which returns multiple partial views.

public class MultiplePartialViewsResult : ActionResult
{
    private const string Separator = "-";
    private PartialViewResult[] _partialViews;

    public MultiplePartialViewsResult(params PartialViewResult[] partialViews)
    {
        _partialViews = partialViews;
    }

    public override void ExecuteResult(ControllerContext context)
    {
        foreach (var partialView in _partialViews)
        {
            partialView.ExecuteResult(context);
            context.HttpContext.Response.Output.Write(Separator);
        }
    }
}

And then I use it as follows:

return new MultiplePartialViewsResult(
             PartialView("~/Views/RowSumView.cshtml", new List<double>() { 1.0 }),
             PartialView("~/Views/ColumnSumView.cshtml", new List<double>() { 2.0 }));

But if I place breakpoint in MultiplePartialViewsResult's constructor I see that model in both cases equals 2.0. It overrides all models with the last model specified in a array.

Try to create couple PartialViews in method and assign it to variable. Then you will notice they all share equivalent model.

Mikhail
  • 9,186
  • 4
  • 33
  • 49
Maximus
  • 3,458
  • 3
  • 16
  • 27
  • 1
    Yes it is correct.If you are trying to return two `model`s to one view, create a `view model` that contains both of the models that you want to send, and make your view's model the new `ViewModel` – Parth Trivedi Jan 10 '16 at 14:19
  • That is the point that I am trying to return to many views.Idea is based on this post where author indicates that models can be distinct. https://www.simple-talk.com/dotnet/asp.net/revisiting-partial-view-rendering-in-asp.net-mvc/ – Maximus Jan 10 '16 at 14:28
  • 1
    Have check last things? It says to use `view model` shared by both `partial view`. – Parth Trivedi Jan 10 '16 at 14:31
  • "In the example, the two partial views use the same view model. This is not a limitation though. " – Maximus Jan 10 '16 at 14:34
  • 1
    Yes .So In your example you have to use single `view model` – Parth Trivedi Jan 10 '16 at 14:36
  • Why would I if an author states it is not obligatory. Apparently something under the cover acts in PartialView that it saves only last model used. – Maximus Jan 10 '16 at 14:38
  • May be. You have to wait for better answer to judge this issue. – Parth Trivedi Jan 10 '16 at 14:45

1 Answers1

6

You can initialize the MultiplePartialViewsResult object in the following manner with new own ViewData / ViewData.Model instances (works fine for me):

return new MultiplePartialViewsResult(
    //PartialView("~/Views/RowSumView.cshtml", new List<double>() { 1.0 }),
    //PartialView("~/Views/ColumnSumView.cshtml", new List<double>() { 2.0 })
    new PartialViewResult() { ViewName = "~/Views/RowSumView.cshtml", ViewData = new ViewDataDictionary() { Model = new List<double>() { 1.0 } } },
    new PartialViewResult() { ViewName = "~/Views/ColumnSumView.cshtml", ViewData = new ViewDataDictionary() { Model = new List<double>() { 2.0 } } }
);

Custom Action Result:

public class MultiplePartialViewsResult : ActionResult {
    private const string Separator = "-";
    private PartialViewResult[] _partialViews;

    public MultiplePartialViewsResult(params PartialViewResult[] partialViews) {
        _partialViews = partialViews;
    }

    public override void ExecuteResult(ControllerContext context) {
        foreach(var partialView in _partialViews) {
            partialView.ExecuteResult(context);
            context.HttpContext.Response.Output.Write(Separator);
        }
    }
}

Controller:

public ActionResult Index() {
    return View();
}
public ActionResult FakeAction() {
    return new MultiplePartialViewsResult(
        //PartialView("~/Views/RowSumView.cshtml", new List<double>() { 1.0 }),
        //PartialView("~/Views/ColumnSumView.cshtml", new List<double>() { 2.0 })
        new PartialViewResult() { ViewName = "~/Views/RowSumView.cshtml", ViewData = new ViewDataDictionary() { Model = new List<double>() { 1.0 } } },
        new PartialViewResult() { ViewName = "~/Views/ColumnSumView.cshtml", ViewData = new ViewDataDictionary() { Model = new List<double>() { 2.0 } } }
    );
}

Views:

Index:

@Html.Action("FakeAction")

ColumnSumView.cshtml / RowSumView.cshtml:

@model List<double>
<ul>
    @foreach(double item in Model) {
        <li>@item</li>
    }
</ul>
Mikhail
  • 9,186
  • 4
  • 33
  • 49
  • That's a workaround but I am wondering why my example is not working. Is there a better approach to pass multiple partial views? – Maximus Jan 26 '16 at 10:55
  • It seems that it is related to holding a ViewData/Model object while rendering a PartialView (a single ViewData per an ActionResult). Possibly, this is expected behavior. I will try to check if there is a better solution. For now, you can use my suggested approach and always initialize each ActionResult/PartialViewResult with a new ViewData/Model instance. – Mikhail Jan 26 '16 at 12:47
  • 3
    This happens because of the [`PartialView`](https://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/Controller.cs) helper of the controller that Maximum used to create each partial result. That helper will set the model in ViewData.Model where ViewData is a property in [the controller](https://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/ControllerBase.cs). Calling twice `PartialResult` will override the ViewData.Model – Daniel J.G. Jan 26 '16 at 13:13