2016-11-22 6 views
0

フォームフィールドが多いMVC 5アプリケーションでビューを持っています。さまざまなリクエストに対して、私は同じビューを使用しますが、強く型付けされた異なるViewModelを使用します。各ViewModelは全く同じフィールドを持ちますが、必須フィールドはリクエストの種類ごとに異なります。実行時にビューにViewModelを動的に割り当てMVC 5

私の質問は、実行時にシナリオに応じて強く型付けされたViewModelを動的に割り当てることができますか?私は、シナリオごとに同じViewをコピーしないようにしようとしています。なぜなら、ビューは、存在するシナリオの数にかかわらず一貫性を保つからです。

例えば、私が選ばれたシナリオに応じて、私が作成したビューに以下のviewmodelsの1を割り当てたい:

public class FirstScenario_ViewModel 
{ 
    [Required] 
    string FirstValue {get; set;} 

    string SecondValue {get; set;} 
} 

public class SecondScenario_ViewModel 
{ 
    string FirstValue {get; set;} 

    [Required] 
    string SecondValue {get; set;} 
} 
+0

1つのオプションは、条件付き検証属性を持つ単一のモデル/ビュー/アクションメソッドを使用することです。 e [foolproof](http://foolproof.codeplex.com/) '[RequiredIf]'またはそれに類する型の属性を使用します。別の方法は、モデルに '基本'クラス/インターフェースを使用し、カスタム 'ModelBinder'を作成して、POSTメソッドで具象クラスを生成することです。 –

+0

恐ろしい!みんなありがとう!締め切り期限が過ぎたために私は完璧な道を進みましたが、これらはすべて良い提案でした。 – bigtri

答えて

0

1つのオプションは、異なるサブクラスを渡してビューを再利用することです。 Razorはアトリビュートを認識して、ビューに送信された具体的なタイプに従ってhtmlを生成します。

サブクラス化は、ソリューションの一部に過ぎません。 2番目の部分は、フォームがポストされると発生する必要があるモデルバインディングです。 コメントのいずれかで説明されているように、カスタムモデルバインダーを作成することで対応できます。 もう1つは、フォームのアクションを微調整して、フォームが正しいビューモデルタイプを処理できるアクションに投稿されるようにすることです。複数のアクションを持つことの利点は、アクションに対してカスタム検証を実装することが簡単になります。

複数のアクションを使用するのは、最も洗練された方法ではないかもしれません。悪い副作用があるかどうかはわかりません。

// This is the base class declared as the view's @model 
// This one would have all the common validations 
public class TestViewModel 
{ 
    public string ModelType { get; set; } 
    public virtual string Prop1 { get; set; } 
    public virtual string Prop2 { get; set; } 
    public virtual string Prop3 { get; set; } 
} 

public class TestViewModel1 : TestViewModel 
{ 
    [Required] 
    public override string Prop1 { get; set; } 
} 

public class TestViewModel2 : TestViewModel 
{ 
    [Required] 
    public override string Prop1 { get; set; } 
    [Required] 
    public override string Prop2 { get; set; } 
} 

とコントローラ:以下

は、サンプルビューモデルである

public class TestController : Controller 
{ 
    // GET: Test 
    public ActionResult Edit(string modelType) 
    { 
     if (modelType == "1") return View(new Models.TestViewModel1() {ModelType = "1"}); 
     if (modelType == "2") return View(new Models.TestViewModel2() {ModelType = "2" }); 
     return View(new Models.TestViewModel() { ModelType = "" }); 
    } 

    [HttpPost] 
    public ActionResult Edit(Models.TestViewModel model) 
    { 
     if (model.Prop1 == null) ModelState.AddModelError("Prop1", "Please type something"); 
     if (ModelState.IsValid) return RedirectToAction("Edit"); 
     return View(model); 
    } 

    [HttpPost] 
    public ActionResult Edit1(Models.TestViewModel1 model) 
    { 
     if (model.Prop1 == null || !model.Prop1.Contains("1")) ModelState.AddModelError("Prop1", "Please type at least one character 1"); 
     if (ModelState.IsValid) return RedirectToAction("Edit", new { modelType = "1" }); 
     return View("Edit", model); 
    } 

    [HttpPost] 
    public ActionResult Edit2(Models.TestViewModel2 model) 
    { 
     if (model.Prop2 == null || !model.Prop1.Contains("2")) ModelState.AddModelError("Prop2", "Please type at least one character 2"); 
     if (ModelState.IsValid) return RedirectToAction("Edit", new { modelType = "2"}); 
     return View("Edit", model); 
    } 
} 

とビュー(@using(Html.BeginForm ..)を見て

@model WebApplication1.Models.TestViewModel 
@{ 
    Layout = null; 
} 
@Scripts.Render("~/bundles/jquery") 
@Scripts.Render("~/bundles/jqueryval") 

@using (Html.BeginForm("Edit" + Model.ModelType, "Test", new {Model.ModelType})) 
{ 
    @Html.AntiForgeryToken() 

    <div class="form-horizontal"> 
     <h4>TestModel</h4> 
     <hr /> 
     @Html.ValidationSummary(true, "", new { @class = "text-danger" }) 
     @DateTime.Now.ToString("o") 
     <br/> 
     @Html.LabelFor(m => m.ModelType) 
     @Html.DisplayFor(m => m.ModelType) 
     <hr /> 
     <div class="form-group"> 
      @Html.LabelFor(model => model.Prop1, htmlAttributes: new { @class = "control-label col-md-2" }) 
      <div class="col-md-10"> 
       @Html.EditorFor(model => model.Prop1, new { htmlAttributes = new { @class = "form-control" } }) 
       @Html.ValidationMessageFor(model => model.Prop1, "", new { @class = "text-danger" }) 
      </div> 
     </div> 

     <div class="form-group"> 
      @Html.LabelFor(model => model.Prop2, htmlAttributes: new { @class = "control-label col-md-2" }) 
      <div class="col-md-10"> 
       @Html.EditorFor(model => model.Prop2, new { htmlAttributes = new { @class = "form-control" } }) 
       @Html.ValidationMessageFor(model => model.Prop2, "", new { @class = "text-danger" }) 
      </div> 
     </div> 

     <div class="form-group"> 
      @Html.LabelFor(model => model.Prop3, htmlAttributes: new { @class = "control-label col-md-2" }) 
      <div class="col-md-10"> 
       @Html.EditorFor(model => model.Prop3, new { htmlAttributes = new { @class = "form-control" } }) 
       @Html.ValidationMessageFor(model => model.Prop3, "", new { @class = "text-danger" }) 
      </div> 
     </div> 

     <div class="form-group"> 
      <div class="col-md-offset-2 col-md-10"> 
       <input type="submit" value="Save" class="btn btn-default" /> 
      </div> 
     </div> 
    </div> 
} 

<div> 
    @Html.ActionLink("Back to List", "Index") 
</div> 
関連する問題