I have a view that contains conditional logic to render partial views within the main view based on conditions in the model. Originally I included the properties required for the partial view in the main page's view model and everything was hunky dory. I simply created the partial view and had it inherit the same view model as the main page like so:

public class SomeViewModel
{
    public int SomeProperty {get; set;}
    public string SomeOtherProperty { get; set; }
    etc ...
    public string PartialViewProperty { get; set; }
}

Then in the partial view:

Inherits="System.Web.Mvc.ViewUserControl<SomeViewModel>"

But now I want to reuse the partial views on pages with different view models, so the partial view can no longer inherit the same view model as it's parent since the parent view models will be different. I thought of creating a separate model for the partial view and include that in the parent view, but in many cases there is only one property required in the partial view. I could just pass the property through ViewBag or something, but I prefer that all my views are strongly typed. If I go with creating a separate model for partial views my models will now look like this:

public class SomeViewModel
{
    public int SomeProperty {get; set;}
    public string SomeOtherProperty { get; set; }    
    public SomePartialViewModel SomeModelObject { get; set; }
}

public class SomePartialViewModel
{
    public string PartialViewProperty { get; set; }
}

I'm sure this would work, but it doesn't feel right. It looks strange to me to see a class with only one property in it. I searched Google & SO for things like "class with only one property" etc and could not find examples of classes with just one property. So my questions are:

  1. Are single property classes OK and I just didn't happen to find any examples?
  2. Is there a better way of doing what I want to do that I am overlooking?
有帮助吗?

解决方案

Are single property classes OK and I just didn't happen to find any examples?

I don't see anything wrong with this, and I know I've used this myself for certain things. The partial itself is still a different view to your main view, so essentially, that single-property class does represent everything the partial would need in order to be rendered.

Having said that, you could just strongly-type the partial to the type of the property in question. For example, taking your code above:

public class SomeViewModel
{
    public int SomeProperty {get; set;}
    public string SomeOtherProperty { get; set; }    
    public SomePartialViewModel SomeModelObject { get; set; }
}

public class SomePartialViewModel
{
    public string PartialViewProperty { get; set; }
}

Rather than making the view strongly-typed against SomePartialViewModel, make it strongly-typed against string instead. That way, your parent view model can be simplified to this:

public class SomeViewModel
{
    public int SomeProperty {get; set;}
    public string SomeOtherProperty { get; set; }
    etc ...
    public string PartialViewProperty { get; set; }
}

And now you can pass the string to the partial:

@Html.Partial("SomeView", Model.PartialViewProperty)

My personal preference is not to do this. The simple reason being that you could pass any string to that view by mistake and the view would compile. Having a dedicated view model for each partial reduces the likelihood of that happening.

Is there a better way of doing what I want to do that I am overlooking?

You could possibly argue that what you're doing is overkill for smaller projects but, like you, I prefer my views to be strongly-typed. Partials are there to be reused and, to me, that means they should be self-sufficient.

Edit

Actually, we should be talking about validation here too. There are two ways you could look at it:

  1. A partial is completely encapsulated for reuse, meaning its validation requirements should not change.
  2. A partial encapsulates the data passed to it but may have different validation requirements based on which view it's called from.

In my mind, the first one is ideally how everything should be. That would mean validation rules would be applied to a dedicated view model for a particular partial.

However, we've all come across situations where validation requirements change. It may not be desirable but it may also not be unreasonable to expect validation requirements to change for a partial. In that case, having a dedicated view model for the partial would be a problem because the validation rules would apply for all invocations of that partial view.

By applying validation to the parent view model instead, you'd be able to change the validation requirements for the partial. For example:

public class ViewModelForViewA
{
    public int Id { get; set; }
    // other properties

    [Required]
    public string PartialProperty { get; set; }
}

public class ViewModelForViewB
{
    public int Id { get; set; }
    // other properties

    // No longer required
    public string PartialProperty { get; set; }
}

However, I still believe the first way is the right way. If a partial had different validation requirements in view A and view B, you could argue that it doesn't represent the same view.

其他提示

They aren't real classes. They are just lowly view models. Don't let their abnormal appearance startle you.

In all seriousness, what you've described, with the partials having their own models is exactly how I have done it. Yes, some folks (and FXCop) will probably harp on you for it, but it's much cleaner and more extensible, as you've described in your post.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top