ModelMetaData, Custom Class Attributes and an indescribable question

前端 未结 2 890
长情又很酷
长情又很酷 2021-02-09 20:13

What I want to do seems so simple.

In my index.cshtml I want to display the WizardStepAttribute Value

So, a user will see at the top of each page,

2条回答
  •  佛祖请我去吃肉
    2021-02-09 20:43

    It can be done, but it is neither easy nor pretty.

    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
    {
        ...
    }
    

    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 attributes,
            Type containerType,
            Func modelAccessor,
            Type modelType,
            string propertyName)
        {
            var modelMetadata = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
            var additionalValues = attributes.OfType().FirstOrDefault();
    
            if (additionalValues != null)
            {
                modelMetadata.AdditionalValues.Add("Name", additionalValues.Name);
                modelMetadata.AdditionalValues.Add("StepNumber", additionalValues.StepNumber);
            }
            return modelMetadata;
        }
    }
    
    
    

    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(this HtmlHelper htmlHelper, Expression> 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(this HtmlHelper htmlHelper, Expression> 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(this HtmlHelper htmlHelper, Expression> expression, IDictionary 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");
        }
    

    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)
    

    Two notes: first, in your Global.asax.cs file, add the following to Application_Start():

            ModelMetadataProviders.Current = new MyModelMetadataProvider();
    

    Second, in the web.config in the Views folder, make sure to add the namespace for your custom HtmlHelper class:

    
      
      
        
          
          
          
          
          
        
      
    
    

    Voila.

    counsellorben

    提交回复
    热议问题