如何使用此页面显示每个视图模型的标题?

发布于 2024-12-13 11:03:44 字数 5557 浏览 2 评论 0原文

好吧,我正在解决一个我已经拖延了三个月的问题。我创建了一个视图,它迭代所有实现 IStepViewModel 的 ViewModel。我需要在视图上显示一个表单标题,以简单的英语指示用户正在处理的当前步骤。我想使用 DataAnnotations 来完成此操作,因此我只需像 [StepTitle("Ownership Information")] 那样装饰每个 ViewModel。我尝试过这样做,但我无法让它发挥作用。这意味着,我的 ModelDataProvider 会被调用,它不会将信息加载到metadata.AdditionalValues 中,当我的视图加载时,我会尝试读取 ViewData.ModelMetadata.AdditionalValues["WizardStep"] 它不存在。

我将在底部包含我的自定义 providerAttribute 类。

Index.cshtml

@using Microsoft.Web.Mvc;
@using Tangible.Models;

@model Tangible.Models.WizardViewModel 

@{ 
    var currentStep = Model.Steps[Model.CurrentStepIndex];
    var progress = ((Double)(Model.CurrentStepIndex) / Model.Steps.Count) * 100;
} 
<script type="text/javascript">
    $(function () {
        $("#progressbar").progressbar({
            value: @progress
        });
    });

</script> 

    @Html.ValidationSummary()
@using (Html.BeginForm())
{ 
<div id="progressbar" style="height:20px;">
<span style="position:absolute;line-height:1.2em; margin-left:10px;">Step @(Model.CurrentStepIndex + 1) out of @Model.Steps.Count</span> 
</div>
<br /> 

    if (Model.CurrentStepIndex > 0)
    { 
        <input type="submit" value="Previous" name="prev" /> 
    }

    if (Model.CurrentStepIndex < Model.Steps.Count - 1)
    { 
        <input type="submit" value="Save &amp; Continue" name="next"  /> 
    }
    else
    { 
        <input type="submit" value="Finish" name="finish" /> 
    }

         @*<input type="submit" value="Save" name="Save" />*@    



    @Html.Serialize("wizard", Model) 

    @Html.Hidden("StepType", Model.Steps[Model.CurrentStepIndex].GetType()) 


    @Html.EditorFor(x => currentStep, null, "") 

    if (Model.CurrentStepIndex > 0)
    { 
        <input type="submit" value="Previous" name="prev" /> 
    }

    if (Model.CurrentStepIndex < Model.Steps.Count - 1)
    { 
        <input type="submit" value="Save &amp; Continue" name="next"  /> 
    }
    else
    { 
        <input type="submit" value="Finish" name="finish" /> 
    }

         @*<input type="submit" value="Save" name="Save" />*@  


}

CustomAttribute

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Security;
using System.Web.Mvc;


namespace Tangible.Attributes
{

    public enum HtmlTextLengthAttribute 
    {
        Description=50,
        Long = 35,
        Default = 60,
        Short = 10,
        Email = 30
    }

    public interface ICustomModelMetaDataAttribute
    {

    }



    [AttributeUsage(AttributeTargets.Class, AllowMultiple= false, Inherited = true)]
    public sealed class WizardStepAttribute : Attribute, ICustomModelMetaDataAttribute
    {
        public WizardStepAttribute() : base() { }

        public String Name { get; set; }
        //public virtual int? Order { get; set; }

        public IDictionary<string, object> WizardStepAttributes()
        {
            IDictionary<string, object> attribs = new Dictionary<string, object>();

            //attribs = this.GetType().GetProperties().ToDictionary(p => p.Name, p=> p.GetValue(this,null)) ; 
            attribs.Add("Name", Name);

            return attribs;
        }

    }

    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
    public class HtmlPropertiesAttribute : Attribute, ICustomModelMetaDataAttribute
    {
        public HtmlPropertiesAttribute()
        {
            Size = (int) HtmlTextLengthAttribute.Default;
        }
        public string CssClass
        {
            get;
            set;
        }

        /// <summary>
        /// Enter the actual number of characters you want to display in the field.
        /// </summary>
        public int Size
        {
            get;
            set;
        }
        public IDictionary<string, object> HtmlAttributes()
        {
            //Todo: we could use TypeDescriptor to get the dictionary of properties and their values
            IDictionary<string, object> htmlatts = new Dictionary<string, object>();
            if (Size != 0)
            {
                htmlatts.Add("size", Size);
            }
            return htmlatts;
        }
    }



}

自定义 ModelMetaDataProvider

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Tangible.Attributes;

namespace Tangible.Providers
{

    public class ModelMetadataProvider : DataAnnotationsModelMetadataProvider
    {

        protected override ModelMetadata CreateMetadata(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 customAttr = attributes.OfType<ICustomModelMetaDataAttribute>();
            if (customAttr != null)
            {
                foreach (var itr in customAttr)
                {
                    metadata.AdditionalValues.Add(itr.GetType().Name, itr);
                }


            }
            return metadata;
        }


    }

    }

Okay, I'm working on a problem that I've been holding off on for three months. I have created a View that iterates through all of my ViewModels that implement IStepViewModel. I need to display a form title on the view that indicates in plain english the current step the user is working on. I would like to do this with DataAnnotations, so I just have to decorate each ViewModel like so [StepTitle("Ownership Information")]. I've tried to do this but I couldn't get it to work. Meaning, that my ModelDataProvider would get called, it would not load the information into metadata.AdditionalValues and when my view gets loaded and I would try to read ViewData.ModelMetadata.AdditionalValues["WizardStep"] it did not exist.

I'll include my custom provider and Attribute classes at the bottom.

Index.cshtml

@using Microsoft.Web.Mvc;
@using Tangible.Models;

@model Tangible.Models.WizardViewModel 

@{ 
    var currentStep = Model.Steps[Model.CurrentStepIndex];
    var progress = ((Double)(Model.CurrentStepIndex) / Model.Steps.Count) * 100;
} 
<script type="text/javascript">
    $(function () {
        $("#progressbar").progressbar({
            value: @progress
        });
    });

</script> 

    @Html.ValidationSummary()
@using (Html.BeginForm())
{ 
<div id="progressbar" style="height:20px;">
<span style="position:absolute;line-height:1.2em; margin-left:10px;">Step @(Model.CurrentStepIndex + 1) out of @Model.Steps.Count</span> 
</div>
<br /> 

    if (Model.CurrentStepIndex > 0)
    { 
        <input type="submit" value="Previous" name="prev" /> 
    }

    if (Model.CurrentStepIndex < Model.Steps.Count - 1)
    { 
        <input type="submit" value="Save & Continue" name="next"  /> 
    }
    else
    { 
        <input type="submit" value="Finish" name="finish" /> 
    }

         @*<input type="submit" value="Save" name="Save" />*@    



    @Html.Serialize("wizard", Model) 

    @Html.Hidden("StepType", Model.Steps[Model.CurrentStepIndex].GetType()) 


    @Html.EditorFor(x => currentStep, null, "") 

    if (Model.CurrentStepIndex > 0)
    { 
        <input type="submit" value="Previous" name="prev" /> 
    }

    if (Model.CurrentStepIndex < Model.Steps.Count - 1)
    { 
        <input type="submit" value="Save & Continue" name="next"  /> 
    }
    else
    { 
        <input type="submit" value="Finish" name="finish" /> 
    }

         @*<input type="submit" value="Save" name="Save" />*@  


}

CustomAttribute

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Security;
using System.Web.Mvc;


namespace Tangible.Attributes
{

    public enum HtmlTextLengthAttribute 
    {
        Description=50,
        Long = 35,
        Default = 60,
        Short = 10,
        Email = 30
    }

    public interface ICustomModelMetaDataAttribute
    {

    }



    [AttributeUsage(AttributeTargets.Class, AllowMultiple= false, Inherited = true)]
    public sealed class WizardStepAttribute : Attribute, ICustomModelMetaDataAttribute
    {
        public WizardStepAttribute() : base() { }

        public String Name { get; set; }
        //public virtual int? Order { get; set; }

        public IDictionary<string, object> WizardStepAttributes()
        {
            IDictionary<string, object> attribs = new Dictionary<string, object>();

            //attribs = this.GetType().GetProperties().ToDictionary(p => p.Name, p=> p.GetValue(this,null)) ; 
            attribs.Add("Name", Name);

            return attribs;
        }

    }

    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
    public class HtmlPropertiesAttribute : Attribute, ICustomModelMetaDataAttribute
    {
        public HtmlPropertiesAttribute()
        {
            Size = (int) HtmlTextLengthAttribute.Default;
        }
        public string CssClass
        {
            get;
            set;
        }

        /// <summary>
        /// Enter the actual number of characters you want to display in the field.
        /// </summary>
        public int Size
        {
            get;
            set;
        }
        public IDictionary<string, object> HtmlAttributes()
        {
            //Todo: we could use TypeDescriptor to get the dictionary of properties and their values
            IDictionary<string, object> htmlatts = new Dictionary<string, object>();
            if (Size != 0)
            {
                htmlatts.Add("size", Size);
            }
            return htmlatts;
        }
    }



}

Custom ModelMetaDataProvider

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Tangible.Attributes;

namespace Tangible.Providers
{

    public class ModelMetadataProvider : DataAnnotationsModelMetadataProvider
    {

        protected override ModelMetadata CreateMetadata(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 customAttr = attributes.OfType<ICustomModelMetaDataAttribute>();
            if (customAttr != null)
            {
                foreach (var itr in customAttr)
                {
                    metadata.AdditionalValues.Add(itr.GetType().Name, itr);
                }


            }
            return metadata;
        }


    }

    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

小嗲 2024-12-20 11:03:44

您可以尝试设计一个元数据感知属性:

public class StepTitleAttribute : Attribute, IMetadataAware
{
    private readonly string _title;
    public StepTitleAttribute(string title)
    {
        _title = title;
    }

    public void OnMetadataCreated(ModelMetadata metadata)
    {
        metadata.AdditionalValues["title"] = _title;
    }
}

然后用它装饰您的视图模型:

[StepTitle("Ownership Information")]
public class MyViewModel
{
    ...
}

并在相应的视图中:

<h2>@ViewData.ModelMetadata.AdditionalValues["title"]</h2>

You could try to design a metadata aware attribute:

public class StepTitleAttribute : Attribute, IMetadataAware
{
    private readonly string _title;
    public StepTitleAttribute(string title)
    {
        _title = title;
    }

    public void OnMetadataCreated(ModelMetadata metadata)
    {
        metadata.AdditionalValues["title"] = _title;
    }
}

then decorate your view model with it:

[StepTitle("Ownership Information")]
public class MyViewModel
{
    ...
}

and in the corresponding view:

<h2>@ViewData.ModelMetadata.AdditionalValues["title"]</h2>
南风起 2024-12-20 11:03:44

我必须对我的观点进行硬编码。这是我唯一的选择。

   @switch (Model.CurrentStepIndex)
    case 0: 
         <h2>Preparer's Information</h2>
        break;
    case 1:
    <h2>Owner's Information</h2>
        break;
    case 2:
    <h2>Physical Location</h2>
        break;
    case 3:
    <h2>About this business</h2>
        break;
    case 4:
    <h2>Describe Business</h2>
        break;
    case 6:
        <h2>Sale or Change of Ownership</h2>
        break;

I had to hard code my my view. It was my only option.

   @switch (Model.CurrentStepIndex)
    case 0: 
         <h2>Preparer's Information</h2>
        break;
    case 1:
    <h2>Owner's Information</h2>
        break;
    case 2:
    <h2>Physical Location</h2>
        break;
    case 3:
    <h2>About this business</h2>
        break;
    case 4:
    <h2>Describe Business</h2>
        break;
    case 6:
        <h2>Sale or Change of Ownership</h2>
        break;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文