【问题标题】:Posting Back DropDownList from Strongly Typed View从强类型视图回发 DropDownList
【发布时间】:2021-03-07 10:33:14
【问题描述】:

这与绑定数据库下拉列表的earlier question 有关。下拉列表正在绑定和填充,但在提交表单时在浏览器中引发“对象引用未设置为对象的实例”错误。

调试时,我在 Html.DropDownListFor(...) 辅助方法的 m => m.SelectedDepartment 参数上添加了一个快速观察,并得到:“无法将 lambda 表达式转换为类型 'object' 因为它不是委托类型”。

查看:

@model BudgetDemo.Models.BudgetsActualsViewModel
@using (Html.BeginForm("GetBudgetsActuals", "BudgetsActuals", FormMethod.Post))
{
    @Html.DropDownListFor(m => m.SelectedDepartment, Model.Departments, 
        "Select Department", new { @class = "form-control" })
}

视图模型:

public class BudgetsActualsViewModel
{
    [Display(Name = "Cost Center/Department")]
    [Required(ErrorMessage = "Cost Center/Department is required.")]
    [StringLength(62)]
    public string SelectedDepartment { get; set; }
    public List<SelectListItem> Departments { get; set; }
}

控制器:

// GET: Render view with dropdowns
public ActionResult GetBudgetsActuals()
{
    repo = new BudgetDemoRepository();
    ModelState.Clear();

    try
    {                
        return View(repo.GetBudgetsActuals());
    }
    catch
    {
        return View("Error");
    }
}

存储库:

public BudgetsActualsViewModel GetBudgetsActuals()
{
    ...
    BudgetsActualsViewModel budgetsActuals = new BudgetsActualsViewModel() 
        { Departments = new List<SelectListItem>() };
    
    // Query returning correct data from DB here

    for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
    {
        budgetsActuals.Departments.Add(                    
            new SelectListItem
            {
                Text = ds.Tables[0].Rows[i]["Department"].ToString(),
                Value = ds.Tables[0].Rows[i]["ListValue"].ToString()
            }
        );
    }

    return budgetsActuals;
}

更新

它现在正在工作。更新/添加了以下代码,以在回发后重新呈现表单,其中包含包含所选部门值的成功消息。

查看:

@model BudgetDemo.Models.BudgetsActualsViewModel
@Html.AntiForgeryToken()

@using (Html.BeginForm("GetBudgetsActuals", "BudgetsActuals",  
    FormMethod.Post))
{
     @Html.ValidationSummary(true, "", new { @class = "text-danger" })

     @if (TempData["SuccessMessage"] != null)
     {
         <p class="alert alert-success"
             id="successMessage">@TempData["SuccessMessage"]</p>
     }

    @Html.DropDownListFor(m => m.SelectedDepartment, Model.Departments, 
        "Select Department", new { @class = "form-control" })
    @Html.ValidationMessageFor(model => model.SelectedDepartment, "", 
        new { @class = "text-danger" })    
}

控制器:

// GET
public ActionResult GetBudgetsActuals()
{
    Populate Department dropdown from DB and Year dropdown (static) here
    repo = new BudgetDemoRepository();
    //ModelState.Clear();

    try
    {
        return View(repo.GetBudgetsActuals());
    }
    catch
    {
        return View("Error");
    }
}

// POST
[HttpPost]
public ActionResult GetBudgetsActuals(BudgetsActualsViewModel model)
{
    try
    {
        repo = new BudgetDemoRepository();
        if (ModelState.IsValid)
        {
            TempData["SuccessMessage"] = "Value of SelectedDepartment is: " 
                + model.SelectedDepartment;
            return View(repo.GetBudgetsActuals(model));
        }
        else
        {
            model.Departments = repo.GetBudgetsActuals().Departments;
            return View(model);
        }
    }
    catch
    {
        return View("Error");
    }
}

Repository - 处理 POST 的新重载方法

public BudgetsActualsViewModel GetBudgetsActuals(BudgetsActualsViewModel model)
{
    ....
    // Get the data again
    ....
 
    budgetsActuals.SelectedDepartment = model.SelectedDepartment;
    for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
    {
        budgetsActuals.Departments.Add(
            new SelectListItem
            {
                Text = ds.Tables[0].Rows[i]["Department"].ToString(),
                Value = ds.Tables[0].Rows[i]["ListValue"].ToString()
            }
         );
     }   
     return budgetsActuals;
}

【问题讨论】:

  • 您需要在控件中有一个 post 方法来接受模型。

标签: c# asp.net asp.net-mvc model-view-controller asp.net-mvc-5


【解决方案1】:

修改controller 以获得支持POST 调用的新api。执行以下操作。

给这个方法添加一个get方法,在加载视图时调用,像这样:

[HttpGet]
public ActionResult GetBudgetsActuals()
{
    repo = new BudgetDemoRepository();
    ModelState.Clear();

    try
    {                
        return View(repo.GetBudgetsActuals());
    }
    catch
    {
        return View("Error");
    }
}

添加提交表单时调用的post方法:

[HttpPost] // Decorate with this attribute
public ActionResult PostBudgetsActuals(BudgetDemo.Models.BudgetsActualsViewModel model)
{
    var selectedDepartment = model.SelectedDepartment;
   // dostuff with the model
   return somethingFromHere;
}

然后像这样改变视图:

@model BudgetDemo.Models.BudgetsActualsViewModel
@using (Html.BeginForm("PostBudgetsActuals", "BudgetsActuals", FormMethod.Post))
{
    @Html.DropDownListFor(m => m.SelectedDepartment, Model.Departments, 
        "Select Department", new { @class = "form-control" })
}

如果您遇到DropDownListFor 方法过载的问题,您也可以尝试如下DropDownList 方法:

@using (Html.BeginForm("PostBudgetsActuals", "BudgetsActuals", FormMethod.Post))
{
    @Html.DropDownList("SelectedDepartment", Model.Departments,
        "Select Department", new { @class = "form-control" })
}

更新

// POST
[HttpPost]
public ActionResult GetBudgetsActuals(BudgetsActualsViewModel model)
{
    try
    {
        repo = new BudgetDemoRepository();
        if (model.SelectedDepartment != null)
        { 
            TempData["SuccessMessage"] = "Value of SelectedDepartment is:
                " + model.SelectedDepartment;
        }
        model.Departments = repo.GetBudgetsActuals().Departments;
        return View(model);
     }
     catch
     {
         return View("Error");
     }
}

【讨论】:

  • 在控制器中,当我返回 View("GetBudgetsActuals") 时,它会在下拉列表中引发与以前相同的错误:对象引用未设置为对象的实例 调试时我得到一个值回发时控制器中的 SelectedDepartment。您的更新无效。仍在处理您的原始答案,因为至少现在已经到达控制器。当我返回该视图时,它与以前一样的 null ref 错误。
  • 您可以随时使用ModelState.IsValid 属性查看模型是否存在验证错误。
  • 没关系,它将向用户显示来自ViewData 的自定义消息。但是,ModelState 在获取错误方面更优雅,因为它会比较您在 Model 类中指定的所有内容,即 [StringLength(62)] 如果超过 62,那么它会告诉您它有验证错误。
  • 想象一下,如果您有几十个其他属性,其验证规则是用装饰属性指定的,那么使用ModelState.IsValid 会更容易,而不是手动比较每个属性。
  • 乐于助人:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-15
相关资源
最近更新 更多