2012-11-13 2 views
1

컨트롤러에서 포스트 백의 하위 클래스 모델을 인식하는 데 문제가 있습니다.DisplayTemplate의 하위 클래스를 사용하는 ASP.NET MVC

db에 저장된 필드 메타 데이터를 사용하여 동적 웹 양식을 만들고 있습니다. 내 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

위의 코드에서 발견 한 QuestionTemplate이 프레임 워크에 의해 우회됩니다. 하위 유형을 인식하고 해당 DisplayTemplate을 대신 사용합니다. @ Html.DisplayFor에서 템플릿 이름을 명시 적으로 정의해야했습니다. – nthpixel

답변

1

모델 바인더 : 귀하의 방법을 변경합니다. 이 방법으로 하위 클래스를 사용하고 템플릿을 표시하려면 고유 한 모델 바인더를 작성해야합니다.

TextBoxQuestion 또는 Question 중 어떤 것이 게시되는지 여부를 확인하기 위해 하나 이상의 속성이 있는지 확인하는 것이 좋습니다.

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

감사합니다. 더 많은 파기와 당신은 행동 매개 변수에 의해 정의 된 객체를 만드는 바인더에 대해 옳았습니다.프레임 워크가 런타임에 형식을 추론 할 정도로 똑똑하기를 바랬습니다. :( – nthpixel

0

한 번에 한 가지 질문 만하는 것처럼 보입니다. 그래서 당신이 정보를 게시 할 때 가장 likeley 당신은 오직 하나의 질문 모음을 보내지 않습니다. 메소드가 기대하는 형식의 인스턴스를 생성합니다

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

View에 전달하는 Form 모델에 대해서는 언급하지 못했고, Question 컬렉션이 있습니다. 따라서 두 가지 이상의 질문이 게시 될 것입니다. 문제를 단순화하기 위해 지금은 한 가지 질문 만하고 있습니다. – nthpixel

+0

메서드에서 Question을 기대하는 경우 ASP.NET MVC 모델 바인더가 실제로 TextBoxQuestion을 전달합니까? – strmstn

관련 문제