2012-10-07 55 views
3

我在一個View上有兩種形式在一個Controller中執行兩個單獨的Action方法。MVC 4當我嘗試提交表單時,Model是空的

第一種形式(frmRefresh)負責獲取數據並將其顯示在窗體上,以便用戶可以選擇某些複選框。一旦提交,數據就會在ViewModel中正確返回並正確顯示在表單上。模板的11條記錄和保證人的3條記錄顯示爲表單上的複選框。

第二種形式(frmProcess)負責獲取表單上的數據(從上面的第一個帖子回來)。用戶在屏幕上進行選擇並根據Controller中的某些邏輯進行處理。我在模型中有List對象,並且不要因爲複雜的對象而使用FormCollection來處理數據。基本上,它們是複選框的集合。我真的需要使用應該在模型中提交的數據,因爲在Controller中處理該數據。

提交第二個表單時,我意識到,如果我將它們放在隱藏字段中(因爲它們處於單獨的表單中),那麼我將無法使用這個ddd,這很好。當我提交第二個表單(frmProcess)時,爲什麼模型視圖活頁夾沒有從表單中獲取數據,將其放入模型中並將其提交給我的GeneratePDF動作方法。?第一,我真的需要一些幫助來理解爲什麼會發生這種情況,第二,我真的需要一個解決方案,它將我的模型數據從表單傳遞到動作方法並對其進行處理。正如你可以在Controller中看到的那樣,在代碼的最後,我列舉了ViewModel中的模板來處理數據。

請大家幫忙,因爲我在工作時完全停留在這個位置,他們依賴於我。我只是不明白爲什麼模型聯編程序不會將表單上的值提交給操作方法進行處理。看起來我錯過了一些東西,允許數據在提交後回到模型中。

下面是我的相關代碼: ViedwModel

public partial class ViewModelTemplate_Guarantors 
    { 
     public int SelectedTemplateId { get; set; } 
     public IEnumerable<PDFTemplate> Templates { get; set; } 

     public int SelectedGuarantorId { get; set; } 
     public IEnumerable<tGuarantor> Guarantors { get; set; } 

     public string LoanId { get; set; } 
     public string SelectedDeptText { get; set; } 
     public string SelectedDeptValue { get; set; } 
     public string LoanType { get; set; } 

     public bool ShowTemps { get; set; } 
     public string Error { get; set; } 
     public string ErrorT { get; set; } 
     public string ErrorG { get; set; } 
     public bool ShowGeneratePDFBtn { get; set; } 
    } 

查看

@model PDFConverterModel.ViewModels.ViewModelTemplate_Guarantors 
@{ 
    ViewBag.Title = "BHG :: PDF Generator"; 
} 
<h2>@ViewBag.Message</h2> 

<div> 

    <table style="width: 1000px"> 
     <tr> 
      <td colspan="5"> 
       <img alt="BHG Logo" src="~/Images/logo.gif" /> 
      </td> 
     </tr> 

     @using (Html.BeginForm("Refresh", "Home", FormMethod.Post, new { id = "frmRefresh" }))  {    <tr> 
       <td> 
       @*@(Html.Kendo().NumericTextBox<int>() 
         .Name("txtLoanID") 
         .Placeholder("Enter numeric value") 
       )*@ 

       @Html.LabelFor(model => model.LoanId) 
       @Html.TextBoxFor(model => model.LoanId) 
       @Html.ValidationMessageFor(model => model.LoanId) 
      </tr> 
      <tr> 
       <td>@Html.LabelFor(model => model.LoanType) 
        @Html.TextBox("SBA", "SBA") 
        @Html.ValidationMessageFor(model => model.LoanType) 
        @*@Html.TextBoxFor(model => model.LoanType)*@ 
       </td> 
       <td> 
        <label for="ddlDept">Department:</label> 
        @(Html.Kendo().DropDownListFor(model => model.SelectedDeptText) 
          .Name("ddlDept") 
          .DataTextField("DepartmentName") 
          .DataValueField("DepartmentID") 
          .Events(e => e.Change("Refresh")) 
          .DataSource(source => 
          { 
           source.Read(read => 
           { 
            read.Action("GetDepartments", "Home"); 
           }); 
          }) 
        ) 
        @Html.ValidationMessageFor(model => model.SelectedDeptText) 
       </td> 
      </tr> 
      <tr> 
       <td colspan="3"> 
        <input type="submit" id="btnRefresh" value='Refresh' /> 
       </td> 
      </tr> 
     } 
     @using (Html.BeginForm("GeneratePDF", "Home", FormMethod.Post, new { id = "frmProcess" }))  {    if (Model.ShowGeneratePDFBtn == true) 
      { 
       if (Model.ErrorT != string.Empty) 
       { 
      <tr> 
       <td colspan="5"> 
        <u><b>@Html.Label("Templates:")</b></u> 

       </td> 
      </tr> 
      <tr> 
       @foreach (var item in Model.Templates) 
       { 
        <td> 
         @Html.CheckBoxFor(model => item.IsChecked) 
         @Html.DisplayFor(model => item.TemplateName) 
        </td> 
       } 
      </tr> 
       } 
       else 
       { 
        Model.Error = Model.ErrorT; 
       } 

       if (Model.ErrorG != string.Empty) 
       { 
      <tr> 
       <td colspan="5"> 
        <u><b>@Html.Label("Guarantors:")</b></u> 
       </td> 
      </tr> 
      <tr> 
       @foreach (var item in Model.Guarantors) 
       { 
        <td> 
         @Html.CheckBoxFor(model => item.isChecked) 
         @Html.DisplayFor(model => item.GuarantorFirstName)&nbsp;@Html.DisplayFor(model => item.GuarantorLastName) 
        </td> 
       } 
      </tr> 
       } 
       else 
       { 
        Model.Error = Model.ErrorG; 
       } 
      <tr> 
       <td> 
        <input type="submit" id="btnGeneratePDF" value='Generate PDF' /> 
       </td> 
      </tr> 
      <tr> 
       <td colspan="5"> 
        @Model.Error 
       </td> 
      </tr> 
      } 
     }  </table> 

</div> 

<script type="text/javascript"> 

    $('btnRefresh').on('click', '#btnRefresh', function() { 
     Refresh(); 
    }); 

    function Refresh() { 

     var LoanID = $("#LoanID").val(); 

     if (LoanID != "") { 
      document.forms["frmTemps"].submit(); 
     } 
    } 
</script> 

控制器

public ActionResult Index(ViewModelTemplate_Guarantors model) 


    { 
       ViewBag.Error = ""; 
       model.ShowGeneratePDFBtn = false; 
       return View("Index", model); 
      } 


// used for the first form "frmRefresh"   [HttpPost] public ActionResult Refresh(ViewModelTemplate_Guarantors model)   { 
      try 
      { 
       model.Error = string.Empty; 

       bool dbHasRows = db.ChkLoanFields(Convert.ToInt32(model.LoanId)); 

       if (!dbHasRows) 
       { 
        model.ShowGeneratePDFBtn = false; 
        model.Error = "Details not available for this LoanId."; 
        return View("Index",model); 
       } 
       else 
       { 
        int TemplateCnt = 0; 
        int GuarantorCnt = 0; 
        //todo - modify 2nd & 3rd parms instead of hardcoding 
        ViewModelTemplate_Guarantors tg = db.SelectViewModelTemplate_Guarantors(Convert.ToInt32(model.LoanId), "All", "All", out TemplateCnt, out GuarantorCnt); 

        if (TemplateCnt > 0) 
         model.Templates = tg.Templates; 
        else 
         model.ErrorT = "Templates not available for this LoanType."; 

        if (GuarantorCnt > 0) 
         model.Guarantors = tg.Guarantors; 
        else 
         model.ErrorG = "Guarantors not available for this LoanId."; 

        model.ShowGeneratePDFBtn = true; 
    // right before the return here, the model is full of data. return View("Index", model);     } 
      } 
      catch (Exception ex) 
      { 
       throw ex; 
      } 
     } [HttpPost] // when I check the data here (via submission from the "frmProcess" form, the model is completely empty, null, etc... WHY???? // i NEED the model data here to perform processing in this action method. public ActionResult GeneratePDF(ViewModelTemplate_Guarantors model)   { 
      try 
      { 
       int FolderNo, GuarantorNum = 0; 
       string Folder, LoanFolder = String.Empty; 
       string FormId, FormName, GuarantorName = String.Empty; 

       int LoanId = Convert.ToInt32(model.LoanId); 
       LoanFolder = LoanId.ToString().PadLeft(8, '0'); 

       //To calculate FolderId based on LoanId 
       if ((LoanId > 0) && (LoanId < 99000)) 
       { 
        FolderNo = ((int)(LoanId/10000) * 10000); 
       } 
       else 
       { 
        FolderNo = ((int)(LoanId/1000) * 1000); 
       } 

       Folder = ((int)FolderNo).ToString(); 
       Folder = Folder.PadLeft(8, '0'); 

       //todo - 2nd parm SelectedValue of dept 
       List<sSRPTFundexDocCodes1_Test_Result> sSRPTFundexDocCodes1 = db.GetFormValues(Convert.ToInt32(model.LoanId), (model.SelectedDeptValue)); 

       if (sSRPTFundexDocCodes1 != null) 
       { 
        foreach (PDFTemplate template in model.Templates)      { 
         if (template.IsChecked == true)       { 

TEMPLATENAME沒有出現在模型後門柱。 這工作正常...值(複選框和相應的名稱顯示在窗體上

但是,發佈GeneratePDF按鈕時,我看到的所有模型是如果複選框被選中(這是偉大的)。在玩過以下很多語句之後(ValueFor,DisplayFor,LabelFor,EditorFor等),模板名稱返回的值是空白的。我需要與複選框相對應的模板名稱。

@ Html.ValueFor(型號=> Model.Templates [I] .TemplateName)

我怎樣才能做到這一點?謝謝你的時間提前......下面是我更新的代碼。查看的

ViewModel public partial class ViewModelTemplate_Guarantors 
    { 
     public ViewModelTemplate_Guarantors() 
     { 
      Templates = new List<PDFTemplate>(); 
      Guarantors = new List<tGuarantor>(); 
     } 

     public int SelectedTemplateId { get; set; } 
     public List<PDFTemplate> Templates { get; set; } 

     public int SelectedGuarantorId { get; set; } 
     public List<tGuarantor> Guarantors { get; set; } 

     public string LoanId { get; set; } 
     public string SelectedDeptText { get; set; } 
     public string SelectedDeptValue { get; set; } 
     public string LoanType { get; set; } 

     public string Error { get; set; } 
     public string ErrorT { get; set; } 
     public string ErrorG { get; set; } 
     public bool ShowGeneratePDFBtn { get; set; } 
    } 

Pertinet部分:

if (Model.ShowGeneratePDFBtn == true) 
      { 
       if (Model.ErrorT == string.Empty) 
       { 
      <tr> 
       <td colspan="5"> 
        <u><b>@Html.Label("Templates:")</b></u> 
       </td> 
      </tr> 
      <tr> 
       @for (int i = 0; i < Model.Templates.Count; i++) 
       { 
        <td> 
         @Html.CheckBoxFor(model => Model.Templates[i].IsChecked) 
         @Html.ValueFor(model => Model.Templates[i].TemplateName)      </td> 
       } 

      </tr> 
       } 
       else 
       { 
      <tr> 
       <td> 
        <b>@Html.DisplayFor(model => Model.ErrorT)</b> 
       </td> 
      </tr> 
       } 

       if (Model.ErrorG == string.Empty) 
       { 
      <tr> 
       <td colspan="5"> 
        <u><b>@Html.Label("Guarantors:")</b></u> 
       </td> 
      </tr> 
      <tr> 
       @for (int i = 0; i < Model.Guarantors.Count; i++) 
       { 
        <td> 
         @Html.CheckBoxFor(model => Model.Guarantors[i].isChecked) 
         @Html.ValueFor(model => Model.Guarantors[i].GuarantorFirstName)&nbsp;@Html.ValueFor(model => Model.Guarantors[i].GuarantorLastName)      </td> 
       } 

      </tr> 
       } 
       else 
       { 
      <tr> 
       <td> 
        <b>@Html.DisplayFor(model => Model.ErrorG)</b> 
       </td> 
      </tr> 
       } 
      }  
      <tr> 
       <td colspan="3"> 
        <input type="submit" name="submitbutton" id="btnRefresh" value='Refresh' /> 
       </td> 
       @if (Model.ShowGeneratePDFBtn == true) 
       { 
        <td> 
         <input type="submit" name="submitbutton" id="btnGeneratePDF" value='Generate PDF' /> 
        </td> 
       } 
      </tr> 
      <tr> 
       <td colspan="5"> 
        @Model.Error 
       </td> 
      </tr> 

控制器:

public ActionResult ProcessForm(string submitbutton, ViewModelTemplate_Guarantors model, FormCollection collection) 

基本上,再次它的正常工作。當表單使用「生成PDF」按鈕發佈帖子時,我會得到每個複選框的選中值,而不是模型中模板的名稱。

我在這裏錯過了什麼?

我提交之前的表單基本上如下所示。這是複選框(Form4)的名稱,我一旦進入ActionResult,就會在我的模型中作爲TemplateID丟失。

public ActionResult ProcessForm(string submitbutton, ViewModelTemplate_Guarantors model, FormCollection collection) 

複選框(選中)Form4

@for (int i = 0; i < Model.Templates.Count; i++) 
       { 
        <td> 
         @Html.CheckBoxFor(model => Model.Templates[i].IsChecked) 
         @Html.DisplayFor(model => Model.Templates[i].TemplateName) 
        </td> 
       } 
+0

正如我在最後一個問題中告訴你的,IEnumerables不能以這種方式綁定。爲了使模型聯編程序綁定它們,它們必須是可變集合(IEnumerable不能),例如List。 –

回答

8

正如我在我的評論中提到。模型聯編程序無法綁定到IEnumerable。

你的模型應該是這樣的:

public partial class ViewModelTemplate_Guarantors 
{ 
    public ViewModelTemplate_Guarantors() { 
     Templates = new List<PDFTemplate>(); // These are important, the model binder 
     Guarantors = new List<tGuarantor>(); // will not instantiate nested classes 
    } 
    public int SelectedTemplateId { get; set; } 
    public List<PDFTemplate> Templates { get; set; } 

    public int SelectedGuarantorId { get; set; } 
    public List<tGuarantor> Guarantors { get; set; } 

    ... 
} 

此外,您認爲應該是這樣的:

... 

@for(int i = 0; i < Model.Templates.Count; i++) // should really use label, not display 
{ 
    <td> 
     @Html.CheckBoxFor(model => Model.Templates[i].IsChecked) 
     @Html.DisplayFor(model => Model.Templates[i].TemplateName) 
    </td> 
} 

... 

@for(int i = 0; i < Model.Guarantors.Count; i++) 
{ 
    <td> 
     @Html.CheckBoxFor(model => Model.Guarantors[i].isChecked) 
     @Html.DisplayFor(model => Model.Gurantors[i].GuarantorFirstName)&nbsp;@Html.DisplayFor(model => Model.Guarantors[i].GuarantorLastName) 
    </td> 
} 

... 

雖然一個更好的選擇是使用一個EditorTemplate,而是這樣做:

... 
@Html.EditorFor(m => m.Templates) 
... 
@Html.EditorFor(m => m.Guarantors) 
... 

然後在〜/ Views/Shared中創建一個名爲EditorTemplates的文件夾,然後創建t wo文件稱爲Templates.cshtmlGuarantors.cshtml

在那些文件你可以這樣做:

@model PDFTemplate 
<td> 
    @Html.CheckBoxFor(model => model.IsChecked) 
    @Html.DisplayFor(model => model.TemplateName) 
</td> 

@model Guarantors 
<td> 
    @Html.CheckBoxFor(model => model.isChecked) 
    @Html.DisplayFor(model => model.GuarantorFirstName)&nbsp;@Html.DisplayFor(model => model.GuarantorLastName) 
</td> 

編輯模板將自動遍歷集合,並將佔正確的命名格式,使模型綁定理解這是一個集合。

+0

哇!我明天將在工作中嘗試你的代碼。我確實在我的應用程序中編寫了代碼,但在我完全訪問數據庫之前無法進行測試。我得到你說的第一部分,但是當我把第二部分放在EditorTemplates中時,我得到了msg「一個表達式樹可能不包含動態操作。」無論如何,如果我只做第一部分 - 沒有出汗,那就沒問題。我在這裏不知道關於MVC的兩件大事。 1,模型聯編程序無法綁定到IEnumerable(這讓我瘋狂)和2,我在回發模型中丟失的其他值不包含「For」。 – sagesky36

+0

我會讓你知道我是如何制定出你的答案的。如果不是像你這樣的人幫助我們新手,我們會迷路。再次感謝您的幫助.... – sagesky36

+0

@ sagesky36 - for語法的原因是因爲它需要爲模型聯編程序創建完整的前綴命名方案才能正確綁定。使用foreach,它會剝去前綴,以便綁定器找不到它應該綁定的位置。我不明白爲什麼當使用EditorTemplates時會出現動態錯誤,您在那裏做的任何事情都使用動態屬性(如ViewData或ViewBag) –

相關問題