问题
I have a viewmodel that has an int StateID
field and a string StateName
field like so:
public class DepartmentViewModel : BaseViewModel, IModelWithId
{
// only show in edit mode
public int StateId { get; set; }
// only show in display mode
public string StateName { get; set; }
}
I have a read only view that uses DisplayForModel
and an update view that uses EditorForModel
. I want the DisplayForModel
view to show the StateName
property, and the EditorForModel
view use the StateID
property (I am actually rendering a dropdownlist based on this).
I have not been able to figure out how to decorate my viewmodel properties to create this behavior.
回答1:
A comment on CodeGrue's answer.
Make the attribute inherit IMetadataAware instead. That way you don't need to build your own DataAnnotationsModelMetadataProvider.
The new attribute would become something like:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public sealed class RenderModeAttribute : Attribute, IMetadataAware
{
public RenderMode RenderMode { get; set; }
public RenderModeAttribute(RenderMode renderMode)
{
RenderMode = renderMode;
}
public void OnMetadataCreated(ModelMetadata metadata)
{
switch (RenderMode)
{
case RenderMode.DisplayModeOnly:
metadata.ShowForDisplay = true;
metadata.ShowForEdit = false;
break;
case RenderMode.EditModeOnly:
metadata.ShowForDisplay = false;
metadata.ShowForEdit = true;
break;
case RenderMode.None:
metadata.ShowForDisplay = false;
metadata.ShowForEdit = false;
break;
}
}
}
public enum RenderMode
{
Any,
EditModeOnly,
DisplayModeOnly
}
回答2:
I wanted a solution that was more generic, so I created a new attribute:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public sealed class RenderModeAttribute : Attribute
{
public RenderMode RenderMode { get; set; }
public RenderModeAttribute(RenderMode renderMode)
{
RenderMode = renderMode;
}
}
public enum RenderMode
{
Any,
EditModeOnly,
DisplayModeOnly
}
And included the following code in my custom DataAnnotationsModelMetadataProvider:
var renderModeAttribute = attributes.OfType<RenderModeAttribute>();
if (renderModeAttribute.Any())
{
var renderMode = renderModeAttribute.First().RenderMode;
switch (renderMode)
{
case RenderMode.DisplayModeOnly:
metadata.ShowForDisplay = true;
metadata.ShowForEdit = false;
break;
case RenderMode.EditModeOnly:
metadata.ShowForDisplay = false;
metadata.ShowForEdit = true;
break;
}
}
So that I could just decorate my model as so:
public class DepartmentViewModel
{
[RenderMode(RenderMode.EditModeOnly)]
public int StateId { get; set; }
[RenderMode(RenderMode.DisplayModeOnly)]
public string StateName { get; set; }
}
回答3:
Here is my custom provider, I add a None render mode
public class CustomModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
protected override ModelMetadata CreateMetadata(System.Collections.Generic.IEnumerable<System.Attribute> attributes, System.Type containerType, System.Func<object> modelAccessor, System.Type modelType, string propertyName)
{
var metadata = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
var renderModeAttribute = attributes.OfType<RenderModeAttribute>();
if (renderModeAttribute.Any())
{
var renderMode = renderModeAttribute.First().RenderMode;
switch (renderMode)
{
case RenderMode.DisplayModeOnly:
metadata.ShowForDisplay = true;
metadata.ShowForEdit = false;
break;
case RenderMode.EditModeOnly:
metadata.ShowForDisplay = false;
metadata.ShowForEdit = true;
break;
case RenderMode.None:
metadata.ShowForDisplay = false;
metadata.ShowForEdit = false;
break;
}
}
return metadata;
}
}
回答4:
Override the templates:
In ~/Shared/EditorTemplates/DepartmentViewModel.ascx
put:
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Namespace.DepartmentViewModel>" %>
<%= Html.LabelFor(x => x.StateId) %>
<%= Html.TextBoxFor(x => x.StateId) %>
And in your ~/Shared/DisplayTemplates/DepartmentViewModel.ascx
:
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Namespace.DepartmentViewModel>" %>
<div><%= Html.Encode(Model.StateName) %></div>
来源:https://stackoverflow.com/questions/2959041/showing-different-fields-in-editorformodel-vs-displayformodel-modes-in-mvc2