2012-11-13 60 views
1

我遇到問題讓我的控制器在回發中識別子類模型。ASP.NET MVC在DisplayTemplate中使用子類

我正在創建一個動態的網頁形式與存儲在數據庫中的字段元數據。對於我的ViewModels,我有兩個父類型

public class Form 
{ 
    public List<Question> Questions { get; set; } 
} 
public class Question 
{ 
    public string QuestionText { get; set; } 
} 

和問題的子類

public class TextBoxQuestion : Question 
{ 
    public string TextAnswer { get; set; } 
    public int TextBoxWidth { get; set; } 
} 

我也有一種觀點認爲,需要一個表單類型,型號和兩個顯示模板,一個問題和一種形式的TextBoxQuestion。

//Views/Form/index.cshtml 
@model Form 
@Html.DisplayFor(m => m.Questions) 

-

//Views/Shared/DisplayTemplates/Question.cshtml 
@model Question 
@if(Model is TextBoxQuestion) 
{ 
    @Html.DisplayForModel("TextBoxQuestion") 
} 

-

//Views/Shared/DisplayTemplates/TextBoxQuestion.cshtml 
@model TextBoxQuestion 
<div> 
    @Model.QuestionText 
    @Html.TextBoxFor(m => m.TextAnswer) 
</div> 

頁面加載時,我的控制器創建TextBoxQuestion的實例,把它添加到問題的收集和傳遞表單對象視圖。一切正常,文本框出現在頁面上。

但是,當我回發給控制器時,代碼無法將問題識別爲TextBoxQuestion。它只將它看作父類型問題。

[HttpPost] 
public ActionResult Index(Form f) 
{ 
    foreach (var q in f.Questions) 
    { 
     if (q is TextBoxQuestion) 
     { 
      //code never gets here 
     } 
     else if (q is Form) 
     { 
      //gets here instead 
     } 
    } 
} 

有什麼我失蹤了嗎?

+0

我不知道如果創建一個Question.cshtml會工作。嘗試將相同的代碼放入Object.cshtml模板中。這是我的理解模板只適用於本地類型,即字符串等 – dreza

+0

只是一個筆記,我發現與上面的代碼,問題DisplayTemplate將繞過框架。它識別子類型,並將使用該DisplayTemplate。我不得不在@ Html.DisplayFor中明確定義模板名稱 – nthpixel

回答

1

模型聯編程序將創建方法所期望類型的實例。如果你想以這種方式使用子類和顯示模板,你需要編寫你自己的模型綁定器。

我會建議檢查是否存在一個或多個屬性,以確定是否發佈了TextBoxQuestionQuestion

ModelBinder的:

public class QuestionModelBinder : IModelBinder 
{ 
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 
    { 
     Question result; 
     ValueProviderResult text = bindingContext.ValueProvider.GetValue("TextAnswer"); 
     if (text != null) // TextAnswer was submitted, we'll asume the user wants to create a TextBoxAnswer 
      result = new TextBoxQuestion { TextAnswer = text.AttemptedValue /* Other attributes */ }; 
     else 
      result = new Question(); 

     // Set base class attributes 
     result.QuestionText = bindingContext.ValueProvider.GetValue("QuestionText").AttemptedValue; 
     return result; 
    } 
} 

然後在Global.asax.cs中把它掛:

ModelBinders.Binders.Add(typeof(Question), new QuestionModelBinder()); 
+0

謝謝strmstn。做了更多的挖掘,並且您正準備創建由Action參數定義的對象的聯編程序。我希望框架足夠聰明,可以在運行時推斷出類型。 :( – nthpixel

0

它看起來像我一次只問一個問題。所以當你最喜歡發佈你的信息時,你只會發送一個而不是一組問題。將您的方法更改爲:

[HttpPost] 
public ActionResult Index(Question q) 
{ 
    if (q is TextBoxQuestion) 
    { 
     //proces TextBoxQuestion 
    } 
    else if (q is Question) 
    { 
     //process generic question 
    } 
} 
+0

我沒有提到我傳遞給View的Form模型有一組問題。所以會有多個問題發佈回來。爲了簡化問題,我現在只處理一個問題。 – nthpixel

+0

如果該方法需要一個問題,ASP.NET MVC模型綁定器是否真的會傳遞一個TextBoxQuestion? – strmstn