ASP.NET MVC在DisplayTemplate中使用子类

时间:2012-11-13 19:18:07

标签: asp.net-mvc razor

我遇到问题让我的控制器在回发上识别子类模型。

我正在创建一个动态Web表单,其中包含存储在db中的字段元数据。对于我的ViewModel,我有两种父类型

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; }
}

我还有一个视图,它将一个Form类型作为Model和两个显示模板,一个用于Question,另一个用于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实例,将其添加到Question集合并将Form对象传递给视图。一切正常,文本框出现在页面上。

但是当我回发到控制器时,代码不会将问题识别为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
        }
    }
}

我有什么遗失的吗?

2 个答案:

答案 0 :(得分: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());

答案 1 :(得分:0)

在我看来,你只是一次只问一个问题。因此,当您发布最相似的信息时,您只发送一个而不是一组问题。将您的方法更改为:

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