2014-01-13 77 views
1

我想用一個視圖來做到這一點,也許這不是最好的方式?如何從不同的ViewModel返回值?

我有一個數據驅動的表單;問題都來自一個問題表,但答案填充一個答覆表。這裏是視圖;

@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> 

這裏是我的視圖模型;

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版本來填充頁面,但我的任務是: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); 
    } 
    } 
} 

我一直在這個問題上工作幾天,現在我只是繞着圈子走。任何幫助或建議,我非常感謝。

+0

順便說一句,讓視圖中顯示的問題號碼基於ID是不好的做法。Id應該完全不知道你的實現。應該有一個單獨的字段用於存儲實際的問題編號。 –

+0

同意。我打算在能夠正常工作時切換到頁碼。但我暫時無法顯示用戶的答案。兩者都困擾着我! – Alex

+0

你的[Route ...]工作嗎?當您導航到該網址時,控制器方法是否執行? –

回答

0

看起來你很迷惑實體模型和ViewModels。在你看來,你參考Template.Models.Question,這似乎是一個實體,而不是一個ViewModel。

該視圖應只引用您的ViewModel,而不是您的實體。並且你的實體和你的ViewModel之間應該建立一些映射機制。我注意到的另一件事是您的實體和您的ViewModel似乎駐留在您的應用程序中相同的命名空間。這不一定是個問題,但可能會讓人困惑,因爲ViewModels僅適用於您的視圖,實體適用於您的持久層。

當前您的代碼通過以下方法獲取問題對象:from q in db.Questions然後您將該問題傳遞給View(問題)。所以你不會在視圖中提供你的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執行映射。問題到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; 
     } 
    } 
} 

此外,請注意上面的變化,我現在正在映射項目,因爲他們被查詢。

+0

你是正確的亞倫,我很困惑的實體和視圖模型。你能否給我任何更多的細節或「擴展方法執行映射」的含義,因爲這是使我困惑的部分? – Alex