【问题标题】:How to return values from a different ViewModel?如何从不同的 ViewModel 返回值?
【发布时间】:2014-01-13 16:04:42
【问题描述】:

我正在尝试使用一个视图来执行此操作,也许这不是最好的方法?

我有一个数据驱动的表单;问题都来自 Questions 表,但答案填充 Response 表。这是视图;

    @using Microsoft.AspNet.Identity
    @model Template.Models.Question

 @{
   ViewBag.Title = "View question";
   var qtype = Model.QuestionTypeId;
   ViewBag.Number = Model.Id - 7;
   Html.BeginForm("ViewQuestion", "Question", FormMethod.Post, new { @class = "form-horizontal", role = "form" }); 
}

<h4>Question #@ViewBag.Number</h4>
<hr />
<h1> @Model.Question1</h1>

@Html.AntiForgeryToken()
<div>

    @switch (qtype)
    {
        case 1:
            // Textbox
            @Html.TextArea("Answer", new { @class = "form-control", rows = "4", col = "5" });<br /><br />
            break;
        case 2:
            // Dropdown
            <select class="form-control" id="Answer">
            @foreach (var item in Model.QuestionOptions.OrderBy(o => o.QuestionOptionRanking))
             {
                 <option value="@item.QuestionOption1">@item.QuestionOption1</option>

             }
             </select><br /><br />
             break;
        case 3:
             //  Checkbox
                 <div class="checkbox">
                 @foreach (var item in Model.QuestionOptions.OrderBy(o => o.QuestionOptionRanking))
                  {
                   <input type="checkbox" name="Answer" value="@item.QuestionOption1" />  @item.QuestionOption1 <br />
                  }
                 </div><br /><br />
                 break;
        case 4:
             //      Radio buttons
             foreach (var item in Model.QuestionOptions.OrderBy(o => o.QuestionOptionRanking))
             {
              <div class="radio">
               <label>
               <input type="radio" name="Answer" value="@item.QuestionOption1" />
               @item.QuestionOption1
               </label>
               </div>
             }<br /><br />
            break;
    }

</div>
<input type="hidden" name="QuestionId" value="@Model.Id" />
<input type="hidden" name="UserId" value="@User.Identity.GetUserId()" />
<div class="form-group">
    <div class="col-md-offset-2 col-md-10">
        <input type="submit" class="btn btn-default" value="Answer" />
    </div>
</div>

这是我的 ViewModel;

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

namespace Template.Models
{
public class GetQuestionViewModel
{

    public int Id { get; set; }

    public int PageNumber { get; set; }

    public string Question1 { get; set; }

    public int QuestionTypeId { get; set; }

    public Nullable<int> LinkedTo { get; set; }

    public Nullable<int> Options { get; set; }

    public Nullable<int> QuestionRanking { get; set; }

    public virtual ICollection<QuestionOption> QuestionOptions { get; set; }

    public virtual QuestionType QuestionType { get; set; }

    public virtual ICollection<Response> Responses { get; set; }

    public virtual ICollection<AspNetUser> AspNetUsers { get; set; }
}

public class ResponseViewModel
{
    [Required]
    public string UserId { get; set; }

    [Required]
    public int QuestionId { get; set; }

    [Required(ErrorMessage = "Please answer the question before submitting")]
    public string Answer { get; set; }

    [Required]
    public string Source { get; set; }

    [Required]
    public string Status { get; set; }

    [Required]
    public System.DateTime DateStamp { get; set; }

    public Nullable<int> Duplicate { get; set; }

    public virtual Question Questions { get; set; }

    public object SelectedValue { get; set; }

    public virtual ICollection<QuestionOption> QuestionOptions { get; set; }
}
}

我根本无法让 GetQuestionViewModel 工作,并使用 .emdx 版本的 Question Model 来填充页面,但我的任务是 a) 在页面上显示每个用户的答案,b) 在页面上显示问题PageNumber 字段,因为可以在单个屏幕上显示任意数量的问题。

这是我的控制器,但正如您所见,注释掉的内容多于工作!

using System.Web.Mvc;
using Template.Models;

namespace Template.Controllers
{
public class QuestionController : Controller
{
    private WebTemplateEntities db = new WebTemplateEntities();

    // GET: /Questions/ViewQuestion/5
    public ActionResult ViewQuestion(int? id)
    {
        if (id == null || id == 0 || id > 12)
        {
            id = 8;
        }
        var question = db.Questions.Find(id);
        if (question == null)
        {
            return HttpNotFound();
        }

        return View(question);
    }

    //        [Route("Questions/{page?}")]
    //public ActionResult ViewQuestion(GetQuestionViewModel model, int? id)
    //{
    //    if (id == null || id == 0 || id > 12)
    //    {
    //        //return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    //        id = 8;
    //        //return RedirectToAction("/ViewQuestion/" + id);
    //    }

    //    var q = db.Questions.Find(id);
    //    var pageId = q.PageNumber;

    //    var questions = from q in db.Questions
    //                    where q.PageNumber == pageId
    //                    orderby q.QuestionRanking
    //                    select q;
    //    return View(questions);
    // }

    // POST: /Questions/ViewQuestion/5
    [HttpPost]
    public ActionResult ViewQuestion([Bind(Include = "QuestionId, Answer, UserId")] ResponseViewModel responseViewModel)
    {
        Response re = new Models.Response();
        re.Answer = responseViewModel.Answer;
        if (re.Answer == null)
        {
            re.Answer = "Work in progress!";
            //    re.Answer = responseViewModel.SelectedValue();
            //    re.Answer = int.Parse(SelectList["Question.QuestionOption1"]);
        }
        re.UserId = responseViewModel.UserId;
        re.QuestionId = responseViewModel.QuestionId;
        var id = responseViewModel.QuestionId;
        re.Source = "Web";
        re.Status = "New";
        re.DateStamp = System.DateTime.Now;
        db.Responses.Add(re);
        db.SaveChanges();

        return RedirectToAction("ViewQuestion/" + (id + 1));
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            db.Dispose();
        }
        base.Dispose(disposing);
    }
  }
}

我已经研究这个问题好几天了,现在我只是在兜圈子。任何帮助或建议我都将不胜感激。

【问题讨论】:

  • 顺便说一句,让视图中显示的问题编号基于 Id 是一种不好的做法。 Id 应该与您的实现完全无关。应该有一个单独的字段用于存储实际的问题编号。
  • 同意。当我可以正常工作时,我计划将其切换到页码。但我目前坚持显示用户的答案。两者都困扰着我!
  • 你的 [Route...] 工作了吗?当您导航到该 url 时,控制器方法是否执行?
  • 此外,该方法似乎返回一个 View(Template.Models.Question) 而不是一个 View(Template.Models.GetQuestionViewModel)

标签: c# asp.net-mvc controller viewmodel


【解决方案1】:

您似乎混淆了实体模型和视图模型。在您的视图中,您引用了Template.Models.Question,它似乎是一个实体而不是一个 ViewModel。

视图应该只引用您的 ViewModel,而不是您的实体。并且应该在您的 Entity 和您的 ViewModel 之间建立一些映射机制。我注意到的另一件事是,您的 Entity 和您的 ViewModel 似乎驻留在应用程序的同一个命名空间中。这不一定是个问题,但可能会让人感到困惑,因为 ViewModel 只与您的视图相关,而实体与您的持久层相关。

目前,您的代码正在通过以下方式获取问题对象:from q in db.Questions,然后您将其传递给 View(question)。因此,您实际上不会在视图中使用您的 ViewModel,它将是您的实体模型。

将您的视图更改为:

@model Template.Models.GetQuestionViewModel

把你的控制器改成这样:

var questions = (from q in db.Questions
                where q.PageNumber == pageId
                orderby q.QuestionRanking
                select q.ToViewModelExtensionMethod()).ToList();

return View(questions);

您必须编写该扩展方法来执行从 Template.Model.Question 到 Template.Model.GetQuestionViewModel 的映射。

希望这会有所帮助。

更新

有关扩展方法的信息,这里是MSDN article

我只使用扩展方法,因为我喜欢语法流动的方式。这是一个简单的例子:

namespace Template.Models.Extensions
{
    public static class QuestionExtensions
    {
        public static GetQuestionViewModel ToViewModelExtensionMethod(this Question question)
        {
            var result = new GetQuestionViewModel();
            result.field1 = question.field1;
            // ... etc
            return result;
        }
    }   
}

另外,请注意上面的更改,我现在在查询项目时映射它们。

【讨论】:

  • 你是对的 Aaron,我对实体和视图模型感到困惑。您能否提供更多详细信息或示例,说明您所说的“执行映射的扩展方法”是什么意思,因为这是真正让我感到困惑的部分?
猜你喜欢
  • 2021-10-18
  • 2021-11-27
  • 1970-01-01
  • 2021-03-30
  • 1970-01-01
  • 1970-01-01
  • 2017-05-05
  • 2017-08-28
  • 1970-01-01
相关资源
最近更新 更多