asp.net 如何使用多选下拉列表绑定多个值

k4emjkb1  于 2023-02-10  发布在  .NET
关注(0)|答案(2)|浏览(190)

我有一个多选下拉列表,需要从中获取值并将其放置在另一个数据表-Incident表中。
我正在从该模型中提取下拉列表的值:

using System.ComponentModel.DataAnnotations;

namespace DWITracker.Model
{
    public class Charge
    {
        [Key]
        public int Id { get; set; }
        [Required]
        [Display(Name = "Charge")]
        public string ChargeCode { get; set; }
        [Required]
        [Display(Name = "Charge Description")]
        public string ChargeDesc { get; set; }
    }
}

这是我的Creat.cs:

using DWITracker.Data;
using DWITracker.Model;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;

namespace DWITracker.Pages.Incidents;

[BindProperties]

public class CreateModel : PageModel
{
    private readonly ApplicationDbContext _db;
    public Incident Incident { get; set; }
    public CreateModel(ApplicationDbContext db)
    {
        _db = db;
    }

    public IEnumerable<City> DisplayPIAddressCityData { get; set; }
    public IEnumerable<County> DisplayPIAddressCountyData { get; set; }
    public IEnumerable<Ethnicity> DisplayPIEthnicityData { get; set; }
    public IEnumerable<int> Charge { get; set; }
    public IEnumerable<SelectListItem> ChargeList { get; set; }

    public async Task<PageResult> OnGet()
    {
        await _db.City.Select(a => a.CityName).ToListAsync();
        DisplayPIAddressCityData = await _db.City.ToListAsync();
        await _db.County.Select(a => a.CountyName).ToListAsync();
        DisplayPIAddressCountyData = await _db.County.ToListAsync();
        await _db.Ethnicity.Select(a => a.EthnicityName).ToListAsync();
        DisplayPIEthnicityData = await _db.Ethnicity.ToListAsync();
        var charges = from c in _db.Charge
                         select c;
        ChargeList = charges.Select(c => new SelectListItem { Value = c.Id.ToString(), Text = c.ChargeCode });
        return Page();
    }
    
    public async Task<IActionResult> OnPost()
    {
        await _db.Incident.AddAsync(Incident);
        await _db.SaveChangesAsync();
        TempData["success"] = "Incident Information added successfully.";
        return RedirectToPage("Index");
    }

}

以下是我观点的相关部分:

<td style="width: 40%">
                    <div class="mb-3">
                        <label asp-for="Incident.ArrestCharges" class="control-label"></label>
                        <select asp-for="Incident.ArrestCharges" class="form-select" multiple="multiple" asp-items="Model.ChargeList">
                            <option value="">Select Applicable Charge(s)</option>
                        </select>
                    </div>
                </td>

现在,如果我从多选下拉列表中选择多个项目,它只会将第一个选择的Id值放入Incident.ArrestCharges列。
我希望它放置一个逗号分隔的多个费用代码(而不是ID)的列表,例如:虚拟磁带库1192-1、虚拟磁带库1192-2、虚拟磁带库1192-2
希望得到一些指导,我需要删除,添加或更改。这是我第一次创建一个多选下拉菜单和绑定它。谢谢!

m4pnthwp

m4pnthwp1#

好的,如果用户选择2个、1个或5个选项?
然后,您将需要添加2,或1或5 recrod在这里。
您不能这样做:
例如:tbl人物

FirstName: John
LastName: Smith
HotelsBooked: 123, 832, 992

所以,通过存储3个值(我预订的酒店),现在怎么办?
您将如何报告、查询或使用sql查询我预订了哪些酒店?
回答:你不能!!!
因此,不要突然开始将多个ID推到一个列中,因为这样做就破坏了使用SQL查询该数据的所有可能性。
换句话说,你要打破你的关系模型,你这样做,然后你的整个系统不能报告说,我预订了什么酒店(在上面的例子)。
既然列的数据类型是"数字"和"ID"?那么当然你不能只插入多个ID值。你可以像我上面的例子所示,如果使用字符串为该列插入多个值,但如前所述,你这样做的瞬间?这是非常相同的瞬间,你打破了关系模型,但它不是真正的一些关系"mumbo-jumbo",但现在您没有实际的方法来使用SQL查询该数据。(甚至将"ID"转换回它们的正确值以显示在报告中或甚至显示在网页中。
所以在上面,如果我想让一个人预订到多个酒店,我不能突然插入多个值,而是需要创建一个新的子表。
tblPeople-我关于此人的上述信息。
tblPeopleBookedInhotels-这是新的子表。
因此,在上面的地方,(我试图在该列中插入多个id),我现在将得到以下内容:
所以,老:

新增:

因此,您可以看到我们希望预订多个酒店的"瞬间",然后我们就不能使用用于保存ONE value和ONE id的一列(hotel_id)。
问题甚至更糟,因为列数据类型无疑是数字类型,因此无论如何都不能插入"id's"字符串。
更糟糕的是,您不想这样做,因为从那时起,查询该数据的任何和所有能力也都将消失。
因此,不要将多个值硬塞到一个列中(该列不允许多个值)。
你必须得到用户的选择,然后循环这些选择,在这个新的表中添加一个全新的行,这个新的表现在可以包含许多酒店预订的"列表"。
我的意思是,您可以尝试将其组装,并将一个列类型从"数字"更改为字符串,然后尝试将多个值作为字符串插入,但您随后会破坏所有现有的软件,这些软件假定并期望该列中只有一个"id"值。

Edit:写出多行的示例

好的,假设我们有"人",然后是他们想要访问的酒店或其他东西的列表框。
所以,我们有这个:
所以,我们将有人员,一个酒店表,当然还有我们的表,允许每个人有多个酒店预订。
那么,tblhotels预订。
我们实际上有这样一种情况:

因此,假设我们有一些标记来显示Person。
没什么特别的,只是有些加价,还有酒店列表框。
因此,我们有了这种标记(并不十分重要)。

<div id="EditRecord" runat="server" style="float:left;display: normal;border:solid 2px;padding:15px;border-radius:12px">

    <h3>Edit Bookings</h3>

    <div style="float:left" class="iForm">
            <label>First Name</label>
            <asp:TextBox ID="tFN" runat="server" f="FirstName" Width="140" /> <br />
            <label>Last Name</label>
            <asp:TextBox ID="tLN" runat="server" f="LastName" Width="140" /> <br />
            <label>City</label>
            <asp:TextBox ID="tCity" runat="server" f="City" Width="140" /><br />
            <label>Prov</label>
            <asp:TextBox ID="tProvince" runat="server" f="Province" Width="75" ></asp:TextBox>
    </div>
    <div style="float:left;margin-left:20px;margin-top:-30px" class="iForm">
        <label>Notes</label> <br />
        <asp:TextBox ID="txtNotes" runat="server" Width="400" TextMode="MultiLine" 
            Height="150px" f="Notes" ></asp:TextBox> <br />
    </div>
    <div style="float:left;margin-left:20px;margin-top:-30px" class="iForm">
        <label>Select Hotels</label> <br />
        <asp:ListBox ID="lstHotels" runat="server"
            DataValueField="id"
            DataTextField="HotelName"
            SelectionMode="Multiple" Height="180px" Width="183px">
        </asp:ListBox>
    </div>
    <div style="clear:both;height:20px"></div>

    <button id="cmdSave" runat="server" class="btn myshadow" onserverclick="cmdSave_ServerClick" >
        <span aria-hidden="true" class="glyphicon glyphicon-floppy-saved"> Save</span> 
    </button>

    <button id="cmdCancel" runat="server" class="btn myshadow" style="margin-left:15px" >
        <span aria-hidden="true" class="glyphicon glyphicon-arrow-left"> Back/Cancel</span>
    </button>

    <button id="cmdDelete" runat="server" class="btn myshadow" style="margin-left:15px">
        <span aria-hidden="true" class="glyphicon glyphicon-trash"> Delete</span>
    </button>

</div>

好的,我们的代码必须加载一个人,然后加载我们想要选择的酒店列表框。
因此,要加载的代码如下:

protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            ViewState["PKID"] = 16;  // assume passed value from preivous page
            LoadData();
        }
    }

    void LoadData()
    {
        string strSQL =
            @"SELECT id, HotelName FROM tblHotelsA
             ORDER BY HotelName";
        lstHotels.DataSource = General.MyRst(strSQL); // load list box
        lstHotels.DataBind();

        strSQL = $@"SELECT * from People WHERE ID = {ViewState["PKID"]}";
        DataTable dtPerson = General.MyRst(strSQL);
        General.FLoader(EditRecord, dtPerson.Rows[0]);
    }

现在我们看到/有了这个:

因此,保存代码必须:
保存对一个人的任何编辑,然后为列表框中选择的每个酒店写出一个新行。
因此,保存代码如下所示:

protected void cmdSave_ServerClick(object sender, EventArgs e)
    {
        int PKID = (int)ViewState["PKID"];
        General.FWriter(EditRecord, PKID, "People"); // send form to database

        // now save/process list box of multiple selected hotels
        // create one new whole row for each hotel selected.
        string strSQL = "SELECT * FROM tblHotelsBooked WHERE ID = 0";
        using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
        {
            using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn))
            {
                conn.Open();
                DataTable dtBookedHotels = new DataTable();
                dtBookedHotels.Load(cmdSQL.ExecuteReader());
                foreach (ListItem OneHotel in lstHotels.Items)
                {
                    if (OneHotel.Selected) 
                    {
                        DataRow MyNewBooking = dtBookedHotels.NewRow();
                        MyNewBooking["People_ID"] = PKID;
                        MyNewBooking["Hotel_id"] = OneHotel.Value;
                        dtBookedHotels.Rows.Add(MyNewBooking);
                    }  
                }
                SqlDataAdapter da = new SqlDataAdapter(cmdSQL);
                SqlCommandBuilder daU = new SqlCommandBuilder(da);
                // now save/send all rows in data table back to database
                da.Update(dtBookedHotels);
            }
        }
    }

现在,我们为每个选定的酒店写出一行数据。
但是,在这个例子中?
我们现在的问题是当我们回到页面再次编辑。
我们现在不仅要加载一个reocrd进行编辑,还要加载列表框中的可能选项,并选择/突出显示每个现有酒店,以便用户可以"看到"和"知道"选择了哪些选项。
如果用户取消选择某个酒店,则必须从tblHotelsBooked中移除/删除该子行。
现在,如果这只是一个值(比如favorote food),或者其他类似的值,那么这个UI可能会非常好,但是,在我的例子中,我们正在选择(并添加)酒店给给定的用户。
然后我们真的需要采用一个用户界面,用户可以看到什么酒店,添加更多的酒店,并删除酒店。
所以,列表框真的应该变成一个类似表格的视图(比如网格视图)。
所以,当我们回到那个reocrd,我们可以更清楚地看到,选择,添加,删除,编辑,改变那些信息。
因此,我们真的应该转储列表框,并使用某种类型的网格。
那么结果将是这样的:

现在,在上面的例子中,我们有"更多"然后选择列表。
那么,如果我们只是有一个选择酒店的列表框呢?当然,但是在这个例子中我们需要"更多",因为我想添加更多的酒店,或者删除它们。
那么,如果我们"坚持"到列表框?
然后我们需要添加代码来选择-突出显示现有的选择。
那么我们需要添加代码来在取消选择时"删除"子行。

8i9zcol2

8i9zcol22#

我希望它放置一个逗号分隔的多个费用代码(而不是ID)列表
这是因为您的下拉列表值已设置为Id,请将该值更改为ChargeCode,如下所示:

ChargeList = charges.Select(c => new SelectListItem { Value = c.ChargeCode, Text = c.ChargeCode });

并且多选下拉列表应该与您要求的List<string>类型属性相匹配,因此您需要创建一个单独的List<string>属性来接收多选值,然后将此列表转换为带逗号的字符串,最后您可以将此字符串值设置为Incident.ArrestCharges
下面是一个完整的工作演示,你可以跟随:
页次

@page
@model CreateModel 
<form method="post">
    <div class="mb-3">
        <label asp-for="Incident.ArrestCharges" class="control-label"></label>
           //change the tag helper value here...........
         <select asp-for="MultiCharge" class="form-select" multiple="multiple" asp-items="Model.ChargeList">
            <option value="">Select Applicable Charge(s)</option>
        </select>
    </div>
    <input type="submit" value="Post" />
</form>

页面模型

[BindProperties]
public class CreateModel : PageModel
{
    //more properties......
    public Incident Incident { get; set; }
    public IEnumerable<SelectListItem> ChargeList { get; set; }
    public List<string> MultiCharge { get; set; }  //receive the multiple selected values
    public async Task<PageResult> OnGet()
    {   
        //other not important code......
        //var charges = from c in _db.Charge
        //             select c;
        //hard-coding here is just for easy testing
        var charges = new List<Charge>()
        {
            new Charge(){ChargeCode="aa",Id=1},
            new Charge(){ChargeCode="bb",Id=2},
            new Charge(){ChargeCode="xx",Id=3}
        };
        // change the Value here....
        ChargeList = charges.Select(c => new SelectListItem { Value = c.ChargeCode, Text = c.ChargeCode });
        return Page();
    }
    public async Task<IActionResult> OnPost()
    {
        //convert list into string with comma.....
        Incident.ArrestCharges = String.Join(",", MultiCharge); 
        //..... 
        return RedirectToPage("Index");
    }

}

相关问题