6


0

MVC2-テンプレート内で親モデル(コンテナー)を取得する方法

DataAnnotationsを使用してMVC2アプリを作成しています。 私は次のモデルを持っています:

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

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

バーのカスタム表示テンプレートを作成したい。 次のテンプレートを作成しました:

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


    <%: Html.LabelForModel() %>


    <%: Html.DisplayForModel()%>
    <%: Html.ActionLink("Some link", "Action", new { id = ??FooId?? }) %>

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

デバッガーでの簡単な調査の後、私はそれを見ることができます:

  1. this.ViewData.ModelMetadata.ContainerType`は FooModel`(as 期待される)

  2. `this.ViewData.TemplateInfo`には非パブリックプロパティがあります 2つの要素「FooModel」と「DateTime?」を含む「VisitedObjects」(「System.Collections.Generic.HashSet」タイプ)。

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

更新:

型安全を可能にする最適なソリューションとして私に見えるので、私はmootinatorの答えを受け入れました。 mootinatorの答えがそれに基づいているので、私はTx3の答えも支持しました。 それにもかかわらず、この種のシナリオではMVCからのより良いサポートが必要だと思います。これは実世界では非常に一般的ですが、サンプルアプリにはないものだと思います。

5 Answer


3


たぶん、新しいクラスを作成することができます。たとえば、UserDateTimeには、null許容のDateTimeと必要な残りの情報が含まれているとします。 次に、UserDateTimeのカスタム表示テンプレートを使用して、必要な情報にアクセスします。

他の種類のソリューションを探しているかもしれないことを理解しています。


2


この機能を親ビューからのHtmlHelper呼び出しに抽出した方が良いと思います。

「RenderSpecialDateTime(this HtmlHelper html、Expression> getPropertyExpression)」のようなものがおそらく仕事をするでしょう。

そうでなければ、Tx3が提案したようなことをしなければなりません。 私は彼の答えを支持したが、これを代替案として投稿した。


1


コントローラでViewDataディクショナリオブジェクトを使用してから、ViewUserControlでそれを取得できませんでしたか? 強く型付けされることはありませんが、…​空の場合は何もしないヘルパーを記述し、値があればログイン履歴ページの例を言うためのリンクを書くことができます。


1


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

ただし、メタデータの作成を担当するプロバイダーのすべてのメソッド(GetMetadataForProperty、Createなど)には署名にコンテナーがないため、Containerプロパティは特定の場合(反映されたコードによるGetMetadataForPropertiesおよびGetMetadataFromProvider)および私の場合にのみ割り当てられます通常はnullでした。

そのため、私がやったことは、新しいメタデータプロバイダーでGetMetadataForPropertyをオーバーライドし、そこで設定することです。

public override ModelMetadata GetMetadataForProperty(Func 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はこのオーバーサイトを修正しているように見えるので、将来的にはリフレクションコードを置き換えることができるかもしれません。


0


この提案がうまくいかない場合は申し訳ありませんが、私はそれを試していませんが、Tx3が提案したことを行うことができません。あなたが望むあらゆるタイプの親を参照する汎用クラスを定義することにより、新しいクラスの束を作成する必要はありませんか?

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

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

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


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

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

}

それを拡張して、「型付きジェネリック」で古い型をカプセル化することもできます。

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

`Inherits =" System.Web.Mvc.ViewUserControl> `のように、どこで使用するテンプレートを明示的に指定する必要はありません。 これは、物事がどのように機能するかということです。