ModelMetaData,自定义类属性和一种说不出的问题 [英] ModelMetaData, Custom Class Attributes and an indescribable question
问题描述
在我index.cshtml我要显示的 WizardStepAttribute
值
In my index.cshtml I want to display the WizardStepAttribute
Value
所以,用户在每个页面的顶部看到,第1步:输入用户信息
So, a user will see at the top of each page, Step 1: Enter User Information
我有一个名为视图模型 WizardViewModel
。该视图模型有一个属性是的IList< IStepViewModel>步骤
I have a ViewModel called WizardViewModel
. This ViewModel has a property that is IList<IStepViewModel> Steps
每个步骤实现了接口IStepViewModel,这是一个空的接口
each "step" implements the Interface IStepViewModel, which is an empty interface.
我有一个名为Index.cshtml视图。此视图显示 EditorFor()
当前步骤。
I have a view called Index.cshtml. This view displays EditorFor()
the current step.
我有一个自定义的模型绑定器,结合了以落实 IStepViewModel
根据 WizardViewModel.CurrentStepIndex 混凝土类的一个新实例code>属性
I have a custom ModelBinder, that binds the View to an new instance of the concrete class implementing IStepViewModel
based on the WizardViewModel.CurrentStepIndex
property
我创建了一个自定义属性 WizardStepAttribute
。
I have created a custom attribute WizardStepAttribute
.
我的脚步类中的每一个定义是这样的。
Each of my Steps classes are defined like this.
[WizardStepAttribute(Name="Enter User Information")]
[Serializable]
public class Step1 : IStepViewModel
....
我有几个问题,虽然。
我的看法是强类型为 WizardViewModel
不是每一个步骤。我不希望有创建视图对于每个具体的实施 IStepViewModel
I have several problems though.
My View is strongly typed to WizardViewModel
not each step. I don't want to have to create a view for each concrete implementation of IStepViewModel
我以为我可以将属性添加到界面,但我必须明确地落实到每个班级。 (因此,这是没有任何好转)
I thought I could add a property to the interface, but then I have to explicitly implement it in each class. (So this isn't any better)
我想我可以在界面中使用反射实现它,但是,你不能引用实例方法的接口。
I'm thinking I could implement it using reflection in the interface but, you can't refer to instances in methods in an interface.
推荐答案
这是可以做到的,但它既不容易,也不pretty。
It can be done, but it is neither easy nor pretty.
首先,我建议增加第二个字符串属性您WizardStepAttribute类,STEPNUMBER,让你的WizardStepAttribute类看起来是这样的:
First, I would suggest adding a second string property to your WizardStepAttribute class, StepNumber, so that your WizardStepAttribute class looks like this:
[AttributeUsage(AttributeTargets.All, AllowMultiple = false)]
public class WizardStepAttribute : Attribute
{
public string StepNumber { get; set; }
public string Name { get; set; }
}
然后,每个班级必须饰:
Then, each class must be decorated:
[WizardAttribute(Name = "Enter User Information", StepNumber = "1")]
public class Step1 : IStepViewModel
{
...
}
接下来,你需要创建一个自定义DataAnnotationsModelMetadataProvider,把你的自定义属性的值,并将其插入到第一步模型的元数据:
Next, you need to create a custom DataAnnotationsModelMetadataProvider, to take the values of your custom attribute and insert them into the Step1 model's metadata:
public class MyModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
protected override ModelMetadata CreateMetadata(
IEnumerable<Attribute> attributes,
Type containerType,
Func<object> modelAccessor,
Type modelType,
string propertyName)
{
var modelMetadata = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
var additionalValues = attributes.OfType<WizardStepAttribute>().FirstOrDefault();
if (additionalValues != null)
{
modelMetadata.AdditionalValues.Add("Name", additionalValues.Name);
modelMetadata.AdditionalValues.Add("StepNumber", additionalValues.StepNumber);
}
return modelMetadata;
}
}
然后,present您的自定义元数据,我建议创建一个自定义的HtmlHelper创建为每个视图标签:
Then, to present your custom metadata, I suggest creating a custom HtmlHelper to create your label for each view:
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types")]
public static MvcHtmlString WizardStepLabelFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
{
return WizardStepLabelFor(htmlHelper, expression, null /* htmlAttributes */);
}
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types")]
public static MvcHtmlString WizardStepLabelFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes)
{
return WizardStepLabelFor(htmlHelper, expression, new RouteValueDictionary(htmlAttributes));
}
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "Users cannot use anonymous methods with the LambdaExpression type")]
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types")]
public static MvcHtmlString WizardStepLabelFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IDictionary<string, object> htmlAttributes)
{
if (expression == null)
{
throw new ArgumentNullException("expression");
}
ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
var values = metadata.AdditionalValues;
// build wizard step label
StringBuilder labelSb = new StringBuilder();
TagBuilder label = new TagBuilder("h3");
label.MergeAttributes(htmlAttributes);
label.InnerHtml = "Step " + values["StepNumber"] + ": " + values["Name"];
labelSb.Append(label.ToString(TagRenderMode.Normal));
return new MvcHtmlString(labelSb.ToString() + "\r");
}
正如你可以看到,自定义帮助您自定义元数据创建一个标签H3
As you can see, the custom helper creates an h3 tag with your custom metadata.
然后,终于,在您看来,放于以下内容:
Then, finally, in your view, put in the following:
@Html.WizardStepLabelFor(model => model)
有两点需要注意:首先,在你的Global.asax.cs文件,添加以下的Application_Start():
Two notes: first, in your Global.asax.cs file, add the following to Application_Start():
ModelMetadataProviders.Current = new MyModelMetadataProvider();
二,在浏览文件夹中的web.config文件时,请务必添加命名空间为您的自定义HtmlHelper类:
Second, in the web.config in the Views folder, make sure to add the namespace for your custom HtmlHelper class:
<system.web.webPages.razor>
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<pages pageBaseType="System.Web.Mvc.WebViewPage">
<namespaces>
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Routing" />
<add namespace="YOUR NAMESPACE HERE"/>
</namespaces>
</pages>
</system.web.webPages.razor>
瞧。
counsellorben
counsellorben
这篇关于ModelMetaData,自定义类属性和一种说不出的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!