質問

DataAnnotations を使用して MVC2 アプリを作成しています。次のモデルがあります:

public class FooModel 
{
    [ScaffoldColumn("false")]
    public long FooId { get; set; }

    [UIHint("BarTemplate")]
    public DateTime? Bar { get; set;}
}

Bar のカスタム表示テンプレートを作成したいと考えています。次のテンプレートを作成しました。

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<DateTime?>" %>

<div class="display-label">
    <span><%: Html.LabelForModel() %></span>
</div>
<div class="display-field">
    <span><%: Html.DisplayForModel()%></span>
    <%: Html.ActionLink("Some link", "Action", new { id = ??FooId?? }) %>
</div>

さて、私の問題はそれです Bar のテンプレート内でモデルから別のプロパティにアクセスしたい. 。他のすべての FooModel プロパティをハードコーディングする必要があるため、FooModel 用に別のテンプレートを作成したくありません。

デバッガーを使って簡単に調査した結果、次のことがわかりました。

  1. this.ViewData.ModelMetadata.ContainerTypeFooModel (予想通り)
  2. this.ViewData.TemplateInfo 非公開の財産があります VisitedObjects(タイプのSystem.Collections.Generic.HashSet<object>)2つの要素が含まれています。FooModel そして DateTime?.

自分の FooModel にアクセスするにはどうすればよいですか?Reflection を使用してハックするつもりはありません。

アップデート:

mootinator の回答は、タイプセーフを可能にする最良の解決策であると思われるため、受け入れました。Mootinator の回答はそれに基づいているため、私は Tx3 の回答にも賛成票を投じました。それにもかかわらず、このようなシナリオでは MVC からのより良いサポートが必要だと思います。現実の世界ではよくあることですが、サンプル アプリには欠けていると思います。

役に立ちましたか?

解決

この提案は、ばかと思われる場合は、申し訳ありませんが、私はそれを試していないが、しかし、あなたはTx3のが好きな親の種類を参照するジェネリッククラスを定義することにより、新しいクラスの束を作成することなく示唆し何ができませんでした?

    public class FooModel 
    {
        [ScaffoldColumn("false")]
        public long FooId { get; set; }

        [UIHint("BarTemplate")]
        public ParentedDateTime<FooModel> Bar { get; set;}

        public FooModel()
        {
            Bar = new ParentedDateTime<FooModel>(this);
        }
    }


    public class ParentedDateTime<T>
    {
        public T Parent {get; set;}
        public DateTime? Babar {get; set; }

        public ParentedDateTime(T parent)
        {
            Parent = parent;
        }

}
あなたも、それが<Parent, Child>を持つ任意の古いタイプをカプセル化するために、一般的な型付き拡張することができます。

また、あなたの強く型付けされたテンプレートは、

のためになるという利点を与えるだろう。

Inherits="System.Web.Mvc.ViewUserControl<ParentedDateTime<FooType>>ので、あなたはどこでも使用するテンプレート明示的に名を持っていません。これは、物事が仕事に意図されている方法ではありません。

他のヒント

たぶん、あなたはのはUserDateTimeを言わせて、新しいクラスを作成することができ、それがNULL可能日時が含まれており、必要な情報の残りの部分でしょう。そして、あなたがUserDateTimeためのカスタム表示テンプレートを使用し、必要な情報へのアクセスを得るでしょう。

私はあなたのソリューションの他の種類を探しているかもしれないことを実現します。

私はあなたが親ビューからHtmlHelperの呼び出しに、この機能を抽出したほうが良いかもしれないと思います。

RenderSpecialDateTime<TModel>(this HtmlHelper html, Expression<Func<TModel,DateTime?>> getPropertyExpression)のようなものは、おそらく仕事をするでしょう。

そうでなければ、あなたはTx3のが提案するもののような何かをする必要があります。私は彼の答えをupvotedが、代替としてこれを掲示ます。

あなたはコントローラーにViewDataを辞書オブジェクトを使用して、ViewUserControlでいることをつかむことができませんでしたか?それは強く型付けされないだろうが、それはそれは価値があった場合などのログイン履歴ページを言って、空、およびリンクの場合...あなたは何もしないようにヘルパーを書くことができます。

MVC 5.0と5.2.2の間のどこかには、「コンテナ」プロパティがModelMetadataクラスに上を加えたように思われます。

メタデータの作成を担当するプロバイダ内のすべてのメソッド(GetMetadataForProperty等の作成)は、その署名にコンテナを持っていないので、

はしかし、コンテナプロパティが(反射されたコードに従ってGetMetadataForPropertiesとGetMetadataFromProvider)のみある場合に割り当てられ、私の場合には、通常はヌルでした。

私は新しいメタデータプロバイダにGetMetadataForPropertyをオーバーライドし、そこに設定されてやってしまったので、何ます:

public override ModelMetadata GetMetadataForProperty(Func<object> modelAccessor, Type containerType, string propertyName)
{
  var propMetaData = base.GetMetadataForProperty(modelAccessor, containerType, propertyName);
  Object container = modelAccessor.Target.GetType().GetField("container").GetValue(modelAccessor.Target);
  propMetaData.Container = container;
  return propMetaData;
}

私はこれが反映している知っているが、それはかなり簡潔です。 MSはので、多分将来的に反射コードを交換することが可能となります。このoversiteを修正していることと思われる。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top