简体   繁体   English

MVC4:从自定义类填充下拉列表

[英]MVC4: populate a drop down list from a custom class

I have a class that I populate when a user navigates to a certain page, /Home/About, within my MVC4 application. 我有一个类,当用户导航到我的MVC4应用程序中的某个页面/ Home / About时,我会填充该类。 I populate a class with data and I would like to have in my view that data in a drop down list. 我用数据填充一个类,我希望在我的视图中有一个下拉列表中的数据。

My class looks like this: (UPDATED) 我的课看起来像这样:(更新)

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;
    }
}

How do I take this populated List of type WorkSection and make that the data source for my drop down list? 如何使用此填充的WorkSection类型列表并将其作为我的下拉列表的数据源? I would like to display the Code and Source field in a concatenated fashion, like "Code:Source" within the drop down list with the ID as the selected item's value. 我想以连接的方式显示代码和源字段,例如下拉列表中的“代码:源”,ID作为所选项的值。

UPDATE for ActionResult, where code will be called from on /Home/About ActionResult的UPDATE,其中代码将从/ 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);
    }

First up, we need a view model to encapsulate the data for the view: 首先,我们需要一个视图模型来封装视图的数据:

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
}

Next up, we need a way to populate the SelectList . 接下来,我们需要一种方法来填充SelectList I wrote a custom method a while ago to do just that: 我刚才写了一个自定义方法来做到这一点:

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);
}

This uses expression trees for type-safety, ensuring problems are caught at compile-time, rather than run-time. 这使用表达式树来实现类型安全,确保在编译时捕获问题,而不是在运行时捕获。 SelectList also uses one property for the text key and one for the value key. SelectList还使用一个属性作为文本键,一个属性作为值键。 In your situation, this obviously creates a problem, because you want to combine Code and Source to form the text key. 在您的情况下,这显然会产生问题,因为您希望将CodeSource组合在一起以形成文本键。 In order to get around that, you'll need to create a new property in WorkSection that combines both: 为了解决这个问题,您需要在WorkSection中创建一个结合了以下两者的新属性:

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

That way, you can use that to create the SelectList as normal. 这样,您可以使用它来正常创建SelectList To do that, your action might like something like: 要做到这一点,你的行动可能会像:

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);
}

You can use that in the view like so: 您可以在视图中使用它,如下所示:

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

One final note on BuildSelectList . 关于BuildSelectList最后一点说明。 The method has saved me a lot of time when dealing with dropdowns in general. 一般来说,这种方法在处理下拉菜单时节省了很多时间。 So much so that I now define it as a public method on a base controller, which I then derive all of my controllers from. 这么多,我现在将它定义为基本控制器上的公共方法,然后我从中派生出所有控制器。 However, if you want to do that, you'll want to mark it with the [NonAction] attribute so it doesn't interfere with routing. 但是,如果要执行此操作,则需要使用[NonAction]属性对其进行标记,以使其不会干扰路由。

Update per comments 每条评论更新

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);
    }
}

Then you'd derive your controllers from BaseController instead: 然后你将从BaseController派生你的控制器:

public HomeController : BaseController
{
    // 
}

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM