如何使用此页面显示每个视图模型的标题?
好吧,我正在解决一个我已经拖延了三个月的问题。我创建了一个视图,它迭代所有实现 IStepViewModel
的 ViewModel。我需要在视图上显示一个表单标题,以简单的英语指示用户正在处理的当前步骤。我想使用 DataAnnotations
来完成此操作,因此我只需像 [StepTitle("Ownership Information")]
那样装饰每个 ViewModel。我尝试过这样做,但我无法让它发挥作用。这意味着,我的 ModelDataProvider 会被调用,它不会将信息加载到metadata.AdditionalValues 中,当我的视图加载时,我会尝试读取 ViewData.ModelMetadata.AdditionalValues["WizardStep"] 它不存在。
我将在底部包含我的自定义 provider
和 Attribute
类。
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;
}
}
}
自定义 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您可以尝试设计一个元数据感知属性:
然后用它装饰您的视图模型:
并在相应的视图中:
You could try to design a metadata aware attribute:
then decorate your view model with it:
and in the corresponding view:
我必须对我的观点进行硬编码。这是我唯一的选择。
I had to hard code my my view. It was my only option.