6

私がやりたいことはとてもシンプルに思えます。

私のindex.cshtmlにWizardStepAttribute値を表示したい

ユーザーは各ページの上部にStep 1: Enter User Information


というViewModelがありWizardViewModelます。このViewModelには次のプロパティがありますIList<IStepViewModel> Steps

各「ステップ」は、空のインターフェイスである Interface IStepViewModel を実装します。

Index.cshtml というビューがあります。このビューにはEditorFor()、現在のステップが表示されます。

プロパティIStepViewModelに基づいて実装する具象クラスの新しいインスタンスにビューをバインドするカスタム ModelBinder があります。WizardViewModel.CurrentStepIndex

カスタム属性を作成しましたWizardStepAttribute

私の各 Steps クラスはこのように定義されています。

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

しかし、いくつかの問題があります。

WizardViewModel私のビューは、各ステップではなく強く型付けされています。具体的な実装ごとにビューを作成する必要はありませんIStepViewModel

インターフェイスにプロパティを追加できると思っていましたが、各クラスで明示的に実装する必要があります。(だから、これは良くない)

インターフェイスでリフレクションを使用して実装できると考えていますが、インターフェイスのメソッドでインスタンスを参照することはできません。

4

2 に答える 2

11

それはできますが、簡単でもきれいでもありません。

まず、2 つ目の文字列プロパティを 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
{
    ...
}

次に、カスタム属性の値を取得して Step1 モデルのメタデータに挿入するために、カスタム DataAnnotationsModelMetadataProvider を作成する必要があります。

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 を作成して各ビューのラベルを作成することをお勧めします。

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

2 つの注意事項: まず、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>

出来上がり。

カウンセラーベン

于 2011-07-27T23:38:47.043 に答える