1

私はこれに似た質問をたくさん見てきましたが、私がすでに持っている以上の答えを持っているものはないようです.

特定のストック UI コントロールを表すいくつかの複雑な型を含み、いくつかの検証ロジックが添付されている ViewModel があります。これらを EditorTemplate/DisplayTemplate に基づいてページにレンダリングする必要があり、開発者がコントローラー内でビューモデルを使用できるように、フォームの送信時に適切にバインドするプロパティも必要です。

これの簡単な例は

public class TestViewModel

{
    public HierarchyField MyField {get; set; }
}

最も簡単な方法として、開発者がこのビュー モデルのエディターを簡単な方法で作成できるようにする必要があります。

@Html.EditorForModel()

HierarchyField の編集可能な部分については、そのタイプのカスタム EditorTemplate 内にフィールドを設定します。

カスタム MetaDataProvider を使用し、IsComplexType をオーバーライドすることで、これをレンダリングできるようになりました。これは、完全に快適ではありませんが、仕事をします。そのソリューションの詳細はこちら ( http://blogs.msdn.com/b/stuartleeks/archive/2010/04/01/collections-and-asp-net-mvc-templated-helpers-part-3.aspx?Redirected =真)

フォームの送信時にモデル バインディングを取得してプロパティを更新し、HierarchyField クラスのメソッドを呼び出してカスタム検証を少し実行し、その呼び出しの結果に基づいて ModelState を更新しようとしています。

最初に、BindProperty オーバーライド内にロジックを持つ DefaultModelBinder のサブクラスを作成し、バインドされているプロパティがこの型であるかどうかを確認しました。これまでのところすべて順調です。問題は、意図した値を取り、その値の検証を試みるインスタンス メソッドを呼び出したいときに発生します。BindProperty メソッドは、プロパティに関するメタデータを検索できる PropertyDescriptor のインスタンスと、値を読み取ることができる ValueProvider を持つ BindingContext を提供しますが、次の複合型のインスタンスは返されません。

bindingContext.ValueProvider.GetValue(propertyDescriptor.Name + ".Value")

propertyDescriptor.Name + ".Value" は、私の EditorTemplate に次のものがあるという事実に相当します。

@Html.TextBoxFor(model => model.Value)

タイプの代わりに、返されたフィールドの Value プロパティへの参照しか取得していないため、String[] を取得します。これを機能させるには、HierarchyField に何らかの ValueProvider を登録する必要があると想定していますが、セットアップするこれらのタイプがいくつかあるため、理想的にはもう少し一般的なものを探しています。そのサブクラスは共通の抽象型です (これらはすべて、値の文字列表現を返す「Value」というプロパティを持っています)。

正直なところ、このプロセス全体が非常に苦痛に思えて、これを行うための本当に簡単なことを見逃しているように感じます。残念ながら、これらのフィールドが多数あるため、これを汎用にする必要があります。このモデル、またはフィールドが検証を処理するための同様のものが必要です。これの多くは、DataAnnotation 検証属性では実行できないためです。特定のビュー モデルに関連付けられたカスタム コードを作成することはできず、特定のフィールドに関連付けられたコードを最小限に抑え、基本クラス (FieldBase) とそのサブクラスに適用されるコードを優先したいと考えています。

誰かがそれを見る必要がある場合は、追加のコードを投稿してください。

4

1 に答える 1

6

いくつかのプロジェクトで複合型とカスタム レンダリングを問題なく使用しています。あなたの質問を誤解しているかもしれませんが、単純化された作業例 (MVC4) を投稿できると思いました。途中で役立つかもしれません。

私の例では、複合型は次のように定義されています。

[ComplexType]
public class AccessType
{
  public bool ReadAccess { get; set; }
  public bool EditAccess { get; set; }
}

モデルは次のように定義されます。

public class UserAccess 
{
  [Key]
  public Int32 UserId { get; set; }
  public AccessType AccessType { get; set; }
}

Views\Shared\DisplayTemplatesにAccessType.cshtmlという名前の次の表示テンプレートを作成して、複合型が表示されているときにそのレンダリングを処理します。

@model [path to complex type].AccessType
@Html.LabelFor(m => m.EditAccess,"Read access")
@Html.DisplayFor(m => m.ReadAccess) 
@Html.LabelFor(m => m.EditAccess, "Edit access")
@Html.DisplayFor(m => m.EditAccess)

Views\Shared\EditorTemplatesにAccessType.cshtmlという名前の次の編集テンプレートを作成して、編集中の複合型のレンダリングを処理します。

@model [path to complex type].AccessType
@Html.LabelFor(m => m.ReadAccess,"Read access")
@Html.CheckBoxFor(m => m.ReadAccess) 
@Html.LabelFor(m => m.EditAccess, "Edit access")
@Html.CheckBoxFor(m => m.EditAccess) 

この複合型を使用するモデルのビュー ファイルに、次の変更を加えました。

_CreateOrEdit.cshtmlファイルにの行を追加して、複合型部分をレンダリングしました。

@Html.EditorFor(m => m.AccessType)

...私が追加したDelete.cshtmlDetails.cshtmlに:

@Html.DisplayFor(m => m.AccessType)

...そしてIndex.cshtmlに追加しました:

@Html.DisplayFor(_ => item.AccessType)

複雑な型をレンダリングして使用するために必要なのはそれだけでした。

問題がより複雑な場合は、説明のためにコードを追加してください。

于 2013-06-05T15:31:25.257 に答える