gpt4 book ai didi

c# - ModelMetaData、Custom Class Attributes 和一个难以描述的问题

转载 作者:太空狗 更新时间:2023-10-29 20:59:38 25 4
gpt4 key购买 nike

我想做的事情看起来很简单。

在我的 index.cshtml 中,我想显示 WizardStepAttribute值(value)

因此,用户将在每个页面的顶部看到 Step 1: Enter User Information


我有一个名为 WizardViewModel 的 ViewModel .这个 ViewModel 有一个属性是 IList<IStepViewModel> Steps

每个“步骤”都实现了接口(interface) IStepViewModel,这是一个空接口(interface)。

我有一个名为 Index.cshtml 的 View 。此 View 显示 EditorFor()当前步骤。

我有一个自定义 ModelBinder,它将 View 绑定(bind)到实现 IStepViewModel 的具体类的新实例基于 WizardViewModel.CurrentStepIndex属性

我创建了一个自定义属性 WizardStepAttribute .

我的每个 Steps 类都是这样定义的。

[WizardStepAttribute(Name="Enter User Information")] 
[Serializable]
public class Step1 : IStepViewModel
....

不过我有几个问题。

我的 View 被强类型化为 WizardViewModel不是每一步。我不想为 IStepViewModel 的每个具体实现都创建一个 View

我以为我可以向接口(interface)添加一个属性,但是我必须在每个类中显式地实现它。 (所以这也好不了多少)

我想我可以在接口(interface)中使用反射来实现它,但是,您不能在接口(interface)的方法中引用实例。

最佳答案

可以做到,但既不简单也不漂亮。

首先,我建议向您的 WizardStepAttribute 类添加第二个字符串属性 StepNumber,以便您的 WizardStepAttribute 类如下所示:

[AttributeUsage(AttributeTargets.All, AllowMultiple = false)]
public class WizardStepAttribute : Attribute
{
public string StepNumber { get; set; }
public string Name { get; set; }
}

然后,每个类都必须被装饰:

[WizardAttribute(Name = "Enter User Information", StepNumber = "1")]
public class Step1 : IStepViewModel
{
...
}

接下来,您需要创建自定义 DataAnnotationsModelMetadataProvider,以获取自定义属性的值并将它们插入到 Step1 模型的元数据中:

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;
}
}

然后,为了展示您的自定义元数据,我建议创建一个自定义 HtmlHelper 来为每个 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 标签。

然后,最后,在您看来,输入以下内容:

@Html.WizardStepLabelFor(model => model)

两个注意事项:首先,在您的 Global.asax.cs 文件中,将以下内容添加到 Application_Start():

        ModelMetadataProviders.Current = new MyModelMetadataProvider();

其次,在 Views 文件夹的 web.config 中,确保为您的自定义 HtmlHelper 类添加命名空间:

<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>

瞧。

辅导员

关于c# - ModelMetaData、Custom Class Attributes 和一个难以描述的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6834814/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com