【问题标题】:MVC4: populate a drop down list from a custom classMVC4:从自定义类填充下拉列表
【发布时间】:2013-11-12 01:05:39
【问题描述】:

当用户导航到我的 MVC4 应用程序中的某个页面 /Home/About 时,我会填充一个类。我用数据填充了一个类,我希望在我的视图中有一个下拉列表中的数据。

我的班级看起来像这样:(已更新)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;

public class WorkSection : List<WorkSection>
{
    [Required]
    [Display(Name = "WorkSection")]
    public int ID { get; set; }
    public string Code { get; set; }

    public SelectList WorkSections { get; set; }

    public WorkSection()
    {
        // Default Constructor
    }

    public WorkSection(int id, string code)
    {
        this.ID = ws_id;
        this.Code = code;
    }
}

如何获取这个 WorkSection 类型的填充列表并将其作为我的下拉列表的数据源?我想以串联的方式显示代码和源字段,例如下拉列表中的“代码:源”,其中 ID 作为所选项目的值。

更新 ActionResult,代码将从 /Home/About 调用

    public ActionResult About()
    {
        WorkSection model = new WorkSection();
        OracleConnection con = new OracleConnection();
        con.ConnectionString = "omitted";

        try
        {
            con.Open();
        }
        catch (Exception ex)
        {
            throw ex;
        }

        try
        {
            OracleDataReader reader = null;
            // Work Section
            OracleCommand cmd = new OracleCommand("SELECT ID, CODE FROM MyTable ORDER BY CODE", con);

            reader = cmd.ExecuteReader();

            while (reader.Read())
            {
                model.Add(new WorkSection()
                {
                    ID = Int16.Parse(reader["ID"].ToString()),
                    Code = reader["CODE"].ToString()
                });
            }

            model.WorkSections = BuildSelectList(model.WorkSections, m => m.ID, m => m.Code);

            con.Close();
            con.Dispose();
        }
        catch (Exception ex)
        {
            throw ex;
        }

        return View(model);
    }

【问题讨论】:

    标签: c# list asp.net-mvc-4


    【解决方案1】:

    首先,我们需要一个视图模型来封装视图的数据:

    public class TestViewModel
    {
        [Required]
        [Display(Name = "Work section")]
        // This represents the selected ID on the dropdown
        public int WorkSectionId { get; set; }
        // The dropdown itself
        public SelectList WorkSections { get; set; }
        // other properties
    }
    

    接下来,我们需要一种方法来填充SelectList。我前段时间写了一个自定义方法来做到这一点:

    private SelectList BuildSelectList<TSource>(IEnumerable<TSource> source,
        Expression<Func<TSource, int>> valueKey, Expression<Func<TSource, string>> textKey,
        object selectedValue = null)
    {
        var selectedValueKey = ((MemberExpression)(MemberExpression)valueKey.Body).Member.Name;
        var selectedTextKey = ((MemberExpression)(MemberExpression)textKey.Body).Member.Name;
    
        return new SelectList(source, selectedValueKey, selectedTextKey, selectedValue);
    }
    

    这使用表达式树来保证类型安全,确保在编译时而不是运行时发现问题。 SelectList 还使用一个属性作为文本键和一个属性作为值键。在您的情况下,这显然会产生问题,因为您想组合 CodeSource 来形成文本键。为了解决这个问题,您需要在WorkSection 中创建一个结合了两者的新属性:

    public string CodeSource
    {
        get { return this.Code + ":" + this.Source; }
    }
    

    这样,您可以像往常一样使用它来创建SelectList。为此,您的操作可能类似于:

    public ActionResult Index()
    {
        var workSections = // ... fetch from database
    
        TestViewModel model = new TestViewModel();
        model.WorkSections = BuildSelectList(workSections, m => m.ID, m => m.CodeSource);
    
        return View(model);
    }
    

    您可以像这样在视图中使用它:

    @Html.DropDownListFor(m => m.WorkSectionId, Model.WorkSections, "--Please Select--")
    @Html.ValidationMessageFor(m => m.WorkSectionId)
    

    关于BuildSelectList 的最后一点说明。在处理一般下拉列表时,该方法为我节省了很多时间。如此之多,以至于我现在将其定义为基本控制器上的公共方法,然后我从中派生所有控制器。但是,如果您想这样做,您需要使用[NonAction] 属性对其进行标记,这样它就不会干扰路由。

    按 cmets 更新

    public class BaseController : Controller
    {
        [NonAction]
        public SelectList BuildSelectList<TSource>(IEnumerable<TSource> source,
            Expression<Func<TSource, int>> valueKey, Expression<Func<TSource, string>> textKey,
            object selectedValue = null)
        {
            var selectedValueKey = ((MemberExpression)(MemberExpression)valueKey.Body).Member.Name;
            var selectedTextKey = ((MemberExpression)(MemberExpression)textKey.Body).Member.Name;
    
            return new SelectList(source, selectedValueKey, selectedTextKey, selectedValue);
        }
    }
    

    然后,您将改为从 BaseController 派生控制器:

    public HomeController : BaseController
    {
        // 
    }
    

    【讨论】:

    • John,请跟我谈谈……在基本控制器上创建一个公共方法。我想我创建了一个其他所有控制器都继承自的控制器,例如 MyController : BaseController?这似乎是个好主意,只是想确保我做对了。
    • @BrianEvans 是的,就是这样,伙计。请稍等,我将添加一个示例,以便您查看。
    • @BrianEvans 好了。
    • 好的,约翰,我已经更新了我上面的类/实体。我留下了一个错误:“System.Web.Mvc.SelectListItem”不包含“ID”的定义,并且找不到接受“System.Web.Mvc.SelectListItem”类型的第一个参数的扩展方法“ID” (您是否缺少 using 指令或程序集引用?)
    • @BrianEvans WorkSection 是您直接传递给视图的模型吗?我的示例依赖于它包含在视图模型中,然后将其传递给视图。
    【解决方案2】:

    @Hmtl.DropdownListFor(m=&gt;m.YourNameForSelectedWorkSectionId, Model.WorkSections.Select(x =&gt; new SelectListItem { Text = x.Code +":"+x.Source, Value = x.ID}))

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-30
      • 1970-01-01
      • 1970-01-01
      • 2014-09-06
      • 1970-01-01
      • 2022-01-11
      相关资源
      最近更新 更多