12

通常、フォームは@ Html.RenderModelでレンダリングしますが、今回は複雑なレンダリングロジックがあり、手動でレンダリングします。1つのプロパティのエディターテンプレートを作成することにしました。コードは次のとおりです(デフォルトのオブジェクトエディタテンプレートの実装からコピーして貼り付けました)。

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<% var modelMetadata = ViewData.ModelMetadata; %>
<% if (modelMetadata.HideSurroundingHtml) { %>
    <%= Html.Editor(modelMetadata.PropertyName) %>
<% } else { %>
    <% if (!String.IsNullOrEmpty(Html.Label(modelMetadata.PropertyName).ToHtmlString())) { %>
        <div class="editor-label"><%= Html.Label(modelMetadata.PropertyName) %></div>
    <% } %>
    <div class="editor-field">
        <%= Html.Editor(modelMetadata.PropertyName) %>
        <%= Html.ValidationMessage(modelMetadata.PropertyName) %>
    </div>
<% } %>

そして、これが私がそれを使う方法です:

@Html.EditorFor(x => x.SomeProperty, "Property") //"Property" is template above

しかし、それは機能しませんでした。ラベルはDisplayNameに関係なくレンダリングされ、エディターはまったくレンダリングされません(Watches Html.Editor(modelMetadata.PropertyNameは空の文字列を示します)。何が問題なのですか?

4

2 に答える 2

12

エディターからエディターを呼び出しています。@ RPM1984 がこの回答のコメントで @darin-dmitrov を言い換えているように:特定のビューの特定のコンテキストで、特定のタイプの実行時に使用できるテンプレートは 1 つだけです。

エディターではなくテキストボックスをレンダリングするようにビューを変更すると、機能します。

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<% var modelMetadata = ViewData.ModelMetadata; %>
<% if (modelMetadata.HideSurroundingHtml)
   { %>
   <%= Html.Editor(modelMetadata.PropertyName) %>
<% }
   else
   { %>
   <% if (!String.IsNullOrEmpty(modelMetadata.DisplayName))
       { %>
       <div class="editor-label"><%= Html.Label(modelMetadata.PropertyName) %></div>
    <% } %>
    <div class="editor-field"><%= Html.TextBox(modelMetadata.PropertyName) %> <%= Html.ValidationMessage(modelMetadata.PropertyName) %></div>
<% } %>

テキスト ボックス (つまり、ドロップダウン リスト) の代わりに別のものをレンダリングする場合は、そのプロパティのテンプレート内でそれを決定してレンダリングする必要があります。または、より多くのエディターに共通する何かがある場合は、通常、それを共有フォルダーの部分ビューに抽出し、単に使用しますHtml.Partial("ViewName")

また、DisplayNameに関係なくラベルがレンダリングされることに関しては、表示名がない場合にラベルがレンダリングされないようにするには、 if 条件を次のように変更します!String.IsNullOrEmpty(modelMetadata.DisplayName)(メイン コード ブロックに既にそのように配置しています)。

編集 この編集は、object.ascx の既定のエディター テンプレートに関連する質問を参照します。これは、 Brad Wilson のブログから取得した object.ascx のコードです。

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<% if (ViewData.TemplateInfo.TemplateDepth > 1) { %>
    <%= ViewData.ModelMetadata.SimpleDisplayText%>
<% }
   else { %>    
    <% foreach (var prop in ViewData.ModelMetadata.Properties.Where(pm => pm.ShowForEdit
                         && !ViewData.TemplateInfo.Visited(pm))) { %>
        <% if (prop.HideSurroundingHtml) { %>
            <%= Html.Editor(prop.PropertyName) %>
        <% }
           else { %>
            <% if (!String.IsNullOrEmpty(Html.Label(prop.PropertyName).ToHtmlString())) { %>
                <div class="editor-label"><%= Html.Label(prop.PropertyName) %></div>
            <% } %>
            <div class="editor-field">
                <%= Html.Editor(prop.PropertyName) %>
                <%= Html.ValidationMessage(prop.PropertyName, "*") %>
            </div>
        <% } %>
    <% } %>
<% } %>

このコードは実際にエディター内から Html.Editor を呼び出しますが、複雑なモデルのプロパティのエディターのリストを作成するループ内にあります。これらの各呼び出しは、対応するエディターを呼び出します (つまり、文字列の場合、string.ascx が表示されます)。これは、文字列ではない「不明な」プロパティがあり、そのための特定のエディターがない場合 (つまり、byte[]) に限られます。 object.ascx を呼び出しますが、これは現在のプロパティのエディターを呼び出しているわけではありません(あなたがやろうとしていること):

オブジェクト テンプレートの主な役割は、複雑なオブジェクトのすべてのプロパティを各プロパティのラベルと共に表示することです。ただし、モデルの NullDisplayText が null の場合はその値を表示する役割もあり、1 レベルのプロパティのみを表示するようにする役割もあります (オブジェクトの「浅いダイビング」とも呼ばれます)。次のブログ投稿では、「詳細な」操作の実行など、このテンプレートをカスタマイズする方法について説明します。


まとめ

短縮版:

同じプロパティのより多くのエディターは、基本的に機能の違いに対する解決策です (「はい/いいえの場合、ここにラジオ グループがあり、そこにドロップダウンが必要です)」。視覚的な違いについては、必要なだけネストできるため、部分ビューを使用する必要があります。 、明示的に名前で呼び出すため、制限が課されないため、潜在的な再帰を防ぐ責任があります。

長いバージョン:

同じ問題があるため、これを調査しています。エディターテンプレートを使用してレンダリング<li>または<td>要素 (構成/テーマに応じて) 内から、ラベルと入力を含む別のエディターを呼び出します (どちらの場合も同じですが、プロパティが bool の場合、入力はラベルの前です)。ここで、入力用の 3 番目のテンプレートを再度呼び出します (ラベル/入力および入力/ラベルのシナリオでコードが重複するのを防ぎます) が、これは機能しません。msdnやその他の関連ソースに関する説明は見つかりませんでしたが、エディターが何も与えない唯一のシナリオは、現在のエディターのコンテキストであるプロパティのエディターをレンダリングしたい場合であることがわかりました(実際には、私がすでに持っているものです)引用:「特定のビューの特定のコンテキストで、特定のタイプの実行時に使用できるテンプレートは1つだけです。」)これについてもう少し考えた後、私は今、彼らがこの制限を課したことは正しいと信じています。プロパティ x は 1 つのエディターを使用してのみレンダリングできるためです。プロパティ x のエディターは必要な数だけ持つことができますが、複数のテンプレートを使用して 1 つのプロパティを一度にレンダリングすることはできません。プロパティ x をレンダリングするためのテンプレートはいずれも、他のテンプレートを使用してプロパティ x のパーツをレンダリングできますが、x に対して (同じまたは異なる) エディターを複数回使用することはできません (2 つ以上のプロパティ x (同じタイプ) を持つ場合と同じロジックが適用されます)。および名前) 同じモデル)。

さらに、現在のプロパティの別のテンプレートを現在のテンプレートに挿入できる場合、現在のプロパティの任意の数のテンプレートを連鎖させることができ、簡単に再帰を引き起こす可能性があるため、何らかの方法でスタックオーバーフローにつながります:)

于 2012-09-01T21:43:01.450 に答える
0

「x.SomeProperty」とはどのような型ですか? 今のところ、その型は Property と呼ばれていると仮定します。

MyModel.cs

public class MyModel
{
    public Property SomeProperty { get; set; }
}

Property.cs

public class Property
{
    [Display(Name="Foo")]
    public int Value { get; set; }
}

ビュー/共有/EditorTemplates/Property.cshtml

@model MvcApplication1.Models.Property

@Html.LabelFor(model => model.Value)
@Html.EditorFor(model => model.Value)
@Html.ValidationMessageFor(model => model.Value)

MyView.cshtml

@Html.EditorFor(model=>model.SomeProperty)

EditorFor ヘルパーに templatename を指定しない場合、名前がSomeProperty のtypeに一致する editortemplate が検索されます。

アップデート:

文字列のカスタム エディター テンプレートを作成するには、次のようにします。

モデル

public class MyModel
{
    public string SomeProperty { get; set; }
}

意見:

@Html.EditorFor(model => model.SomeProperty,"Property")

または、次のようにします。

モデル:

public class MyModel
{
    [DataType("Property")]
    public string SomeProperty { get; set; }
}

意見:

@Html.EditorFor(model => model.SomeProperty) 

ビュー/共有/EditorTemplates/Property.cshtml:

@model string

@Html.Raw("I'm using property editortemplate:")
@Html.Label(ViewData.ModelMetadata.PropertyName)
@Html.Editor(ViewData.ModelMetadata.PropertyName)
@Html.ValidationMessage(ViewData.ModelMetadata.PropertyName)
于 2012-08-30T10:58:44.150 に答える