5

I have two views: a partial view, and a view that encapsulates the partial view using @Html.RenderPartial("_PartialView"). Each has its own ViewModel:

public class PartialViewModel 
{
    // properties, etc.
}

public class MainViewModel 
{
    public PartialViewModel p { get; set; }
    // properties, etc.
}

I'm getting dictionary errors when I load up the second view (the one that uses MainViewModel), because this view and the partial view it encapsulates are using two different ViewModels. I can't have them use the same ViewModel, because the partial view is rendered inside many other different views.

To be clear, both of these views contain forms, with the partial view representing all of the shared fields between forms. Given this, do I have any options, or am I simply attempting to do something that does not fit within the MVC design constraints?

Community
  • 1
  • 1
alex
  • 6,818
  • 9
  • 52
  • 103

2 Answers2

4

you are going to want to design this a little differently . The main view will have a Model - lets call it MainModel, and the partial View can have a Model - we'll call it PartialModel

public class PartialModel 
{
   /// props
}

public class MainViewModel 
{
    public PartialModel Partial { get; set; }
    // properties, etc.

    // per comments in other answer you may want something like this
    public MainViewModel()
    {
      Partial = new PartialModel();
    }
}

then your main View will have

@model MainViewModel

then in the middle of the main view you have something like

@{ Html.RenderPartial("myPartialView", Model.Partial); }

Notice the braces around Html.RenderPartial. They're needed because RenderPartial return is void.

When you render the partial view you can also pass in the Model to it, if it is designed properly then the model that the partial needs will already be accessable from the main view's model

Martin
  • 22,212
  • 11
  • 70
  • 132
Scott Selby
  • 9,420
  • 12
  • 57
  • 96
  • I think this was what I was missing - the second parameter of `@Html.RenderPartial`. Thanks. – alex Nov 04 '14 at 20:20
  • 1
    @alex, For additional information, if you don't specify the model when using `RenderPartial` by default it will use the main views `ViewDataDictionary` so it passes `MainViewModel` to the partial, but since the partial expects `PartialViewModel` you get the errors. –  Nov 05 '14 at 00:55
2

You can do this, but in your controller you're going to need to declare a new MainViewModel and assign to its PartialViewModel a new PartialViewModel.

Ex:

public class Controller {
    public ActionResult Index(){
        var mainViewModel = new MainViewModel { PartialViewModel = new PartialViewModel() };
        return View(mainViewModel);
    }
}

Now, I would delegate the creation of these models to a factory, but that's more advanced and not necessary until you get into refactoring.

Scott Selby
  • 9,420
  • 12
  • 57
  • 96
C Bauer
  • 5,003
  • 4
  • 33
  • 62
  • why is this up-voted? when you RenderPartial() you are not calling a controller , you are just directly rendering a view , the model has to be passed from the view. You have to specify which model like in my answer. Some design patterns just always use the same view model , and they are huge , if that is the case then you can just renderpartial without specificing a model and it will use the same model from the parent view – Scott Selby Nov 05 '14 at 02:50
  • @ScottSelby It *was* most likely upvoted because if you try to access the property of a sub view model that has not been initialized you would get a NullReferenceException because it won't be initialized by default. – C Bauer Nov 05 '14 at 03:33
  • no - it will as long as the master model initialzes it. All this code does is just help when you do RedirectToAction("action", "controller" ) but has nothing at all to do with @Html.RenderPartial – Scott Selby Nov 05 '14 at 03:36
  • "It will as long as the master model initializes it"? So in other words it won't do it by default and OP will need to do so or the page will crash? I see an issue with your answer in that case, since it doesn't cover that. He already marked you as the answer and my answer will help someone who failed to initialize their sub view model. You need to reevaluate your reason for downvoting, since someone clearly found there to be value in my contribution and you're just downvoting for no reason. – C Bauer Nov 05 '14 at 03:40
  • yea - I get what your saying , this could help someone with something similar . This is just when an action is called and the action calls a view , the OP question was about when a view is called directly. I believe that the .Net framework will actually initialize a new default version of the object and prevent an error – Scott Selby Nov 05 '14 at 03:43
  • Think about that. You create a viewmodel with a property that is a subviewmodel. You initialize your viewmodel but leave the sub null. Then you use the subviewmodel as an argument to a renderpartial (using your code). If anywhere in that subviewmodel view you use Model.{PropertyName} (like for instance, Model.Title to display the title), you're doing null.Title. Boom, runtime exceptions all around. Leave the downvote if you're sure that's how it works, but I'm building a site right now that is suffering from this kind of issue. – C Bauer Nov 05 '14 at 03:49