ฉันจะทำให้ ASP.NET MVC SelectList นี้ทำงานได้อย่างไร


126

ฉันสร้างรายการที่เลือกในตัวควบคุมของฉันเพื่อแสดงในมุมมอง

ฉันกำลังพยายามสร้างมันขึ้นมาทันทีสิ่งที่ .. เช่นนี้ ...

myViewData.PageOptionsDropDown = 
   new SelectList(new [] {"10", "15", "25", "50", "100", "1000"}, "15");

มันคอมไพล์ แต่ผลลัพธ์แย่ ...

<select id="PageOptionsDropDown" name="PageOptionsDropDown">
    <option>10</option>
    <option>15</option>
    <option>25</option>
    <option>50</option>
    <option>100</option>
    <option>1000</option>
</select>

สังเกตว่าไม่มีการเลือกรายการใด?

จะแก้ไขได้อย่างไร ??


1
หกคำตอบ ... หนึ่งรายการโปรด ... ไม่มีการโหวตเพิ่ม: / ฉันจะให้ +1
womp

คำตอบ:


128

นี่คือวิธีที่ฉันทำ

IList<Customer> customers = repository.GetAll<Customer>();
IEnumerable<SelectListItem> selectList = 
    from c in customers
    select new SelectListItem
    {
        Selected = (c.CustomerID == invoice.CustomerID),
        Text = c.Name,
        Value = c.CustomerID.ToString()
    };

แวบที่สองฉันไม่แน่ใจว่าฉันรู้ว่าคุณเป็นอย่างไร ...


2
ขอบคุณสิ่งนี้ช่วยให้ฉันคิดออก
Cadoo

6
ไม่ได้แก้ไขปัญหารายการที่เลือก แต่เป็นวิธีที่ดีในการหลีกเลี่ยงสายเวทย์สำหรับรายการที่เลือก! Cheers
Alan Christensen

11
ในการแก้ไขปัญหาสินค้าที่เลือกเพิ่มรหัสต่อไปนี้: ลูกค้าที่เลือกปัจจุบันอยู่SelectList sList = new SelectList(selectList, "Text", "Value", selected);ที่ไหนselected
jao

68

ฉันใช้วิธีการขยาย:

การใช้

var departmentItems = departments.ToSelectList(d => d.Code + 
                                               " - " + d.Description,
                                               d => d.Id.ToString(),
                                               " - ");

var functionItems = customerFunctions.ToSelectList(f => f.Description, 
                                                   f => f.Id.ToString(), 
                                                   " - ");

กับ

public static class MCVExtentions
{
    public static List<SelectListItem> ToSelectList<T>(
        this IEnumerable<T> enumerable, 
        Func<T, string> text, 
        Func<T, string> value, 
        string defaultOption)
    {
        var items = enumerable.Select(f => new SelectListItem()
                                     {
                                         Text = text(f), 
                                         Value = value(f) 
                                     }).ToList();
        items.Insert(0, new SelectListItem()
                    {
                        Text = defaultOption, 
                        Value = "-1" 
                    });
        return items;
    }
}

ดี ฉันได้เพิ่ม Func ที่เลือกตัวเลือก defaultValue และโอเวอร์โหลดครั้งที่สองโดยไม่มีค่าเริ่มต้นใด ๆ ที่จะระบุและสิ่งนี้ใช้ได้ผล อย่างไรก็ตามถ้าคุณต้องการสร้างประเภทผลตอบแทน IEnumerable <SelectListItem> คุณสามารถใช้ไวยากรณ์ผลตอบแทนที่ได้ผลตอบแทนเพื่อให้รูปลักษณ์นี้ดูสะอาดตาจริงๆ
Chris Meek

48

การใช้ตัวสร้างที่ยอมรับitems, dataValueField, dataTextField, selectedValueเป็นพารามิเตอร์:

ViewData["myList"] = 
                new SelectList(new[] { "10", "15", "25", "50", "100", "1000" }
                .Select(x => new {value = x, text = x}), 
                "value", "text", "15");

จากนั้นในมุมมองของคุณ:

<%=Html.DropDownList("myList") %>

3
เพื่อนดี :) ฉันชอบ! ฉันกำลังพยายามทำสิ่งนี้ .. แต่ฉันไม่สามารถรับส่วน. เลือก (.. ) ได้ .. ดี :) ฉันจะลองใช้ที่บ้านในภายหลัง :)
Pure.Krome

1
Heya Cagdas ใช้งานได้ดียกเว้นไม่ได้เลือกฟิลด์ที่เลือกไว้ ความคิดใด นี่คือบั๊กใน MVC หรือไม่
Pure.Krome

2
รายการที่เลือกจะทำงานเมื่อคุณเพิ่มรายการ SelectList ลงในออบเจ็กต์ ViewData (เช่นใน ViewData ["myList"] = new SelectList .. ) จากนั้นแสดงผลด้วย <% = Html.DropDownList ("myList")%> ฉันไม่สามารถทำให้รายการที่เลือกทำงานได้หากไม่ทำแบบนี้ แปลก.
Çağdaş Tekin

@Cagdas - สวัสดีอีกครั้งเพื่อน .. ฉันยังไม่เข้าใจสิ่งนี้ :( สิ่งนี้เกี่ยวกับ ViewData คืออะไร ??? ฉันมี ViewData ที่พิมพ์อย่างรุนแรงและเป็นทรัพย์สินของตัวเอง .... ???
Pure.Krome

@ Pure.Krome - ฉันเอาคุณสมบัตินั้นมาจากตัวอย่างของคุณในคำถาม ตอนนี้ฉันกำลังแก้ไขตัวอย่างโค้ด โปรดดูการแก้ไขของฉันในไม่กี่วินาที
Çağdaş Tekin

19

จากคำตอบของ Thomas Stock ฉันได้สร้างToSelectListวิธีการที่มากเกินไปเหล่านี้:

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

public static partial class Helpers
{
    public static IEnumerable<SelectListItem> ToSelectList<T>(this IEnumerable<T> enumerable, Func<T, object> value, bool selectAll = false)
    {
        return enumerable.ToSelectList(value, value, selectAll);
    }

    public static IEnumerable<SelectListItem> ToSelectList<T>(this IEnumerable<T> enumerable, Func<T, object> value, object selectedValue)
    {
        return enumerable.ToSelectList(value, value, new List<object>() { selectedValue });
    }

    public static IEnumerable<SelectListItem> ToSelectList<T>(this IEnumerable<T> enumerable, Func<T, object> value, IEnumerable<object> selectedValues)
    {
        return enumerable.ToSelectList(value, value, selectedValues);
    }

    public static IEnumerable<SelectListItem> ToSelectList<T>(this IEnumerable<T> enumerable, Func<T, object> value, Func<T, object> text, bool selectAll = false)
    {
        foreach (var f in enumerable.Where(x => x != null))
        {
            yield return new SelectListItem()
            {
                Value = value(f).ToString(),
                Text = text(f).ToString(),
                Selected = selectAll
            };
        }
    }

    public static IEnumerable<SelectListItem> ToSelectList<T>(this IEnumerable<T> enumerable, Func<T, object> value, Func<T, object> text, object selectedValue)
    {
        return enumerable.ToSelectList(value, text, new List<object>() { selectedValue });
    }

    public static IEnumerable<SelectListItem> ToSelectList<T>(this IEnumerable<T> enumerable, Func<T, object> value, Func<T, object> text, IEnumerable<object> selectedValues)
    {
        var sel = selectedValues != null
            ? selectedValues.Where(x => x != null).ToList().ConvertAll<string>(x => x.ToString())
            : new List<string>();

        foreach (var f in enumerable.Where(x => x != null))
        {
            yield return new SelectListItem()
            {
                Value = value(f).ToString(),
                Text = text(f).ToString(),
                Selected = sel.Contains(value(f).ToString())
            };
        }
    }
}

ในคอนโทรลเลอร์ของคุณคุณอาจทำสิ่งต่อไปนี้:

var pageOptions = new[] { "10", "15", "25", "50", "100", "1000" };
ViewBag.PageOptions = pageOptions.ToSelectList(o => o, "15" /*selectedValue*/);

และสุดท้ายในมุมมองของคุณให้ใส่:

@Html.DropDownList("PageOptionsDropDown", ViewBag.PageOptions as IEnumerable<SelectListItem>, "(Select one)")

จะทำให้ได้ผลลัพธ์ที่ต้องการ - แน่นอนคุณสามารถ"(Select one)"เว้น optionLabel ไว้ด้านบนหากคุณไม่ต้องการให้รายการว่างรายการแรก:

<select id="PageOptionsDropDown" name="PageOptionsDropDown">
<option value="">(Select one)</option>
<option value="10">10</option>
<option selected="selected" value="15">15</option>
<option value="25">25</option>
<option value="50">50</option>
<option value="100">100</option>
<option value="1000">1000</option>
</select>

อัปเดต:รายการโค้ดที่แก้ไขสามารถพบได้ที่นี่พร้อมความคิดเห็น XML


13

ปัญหาคือ SelectList ทำงานตามที่ออกแบบไว้ จุดบกพร่องอยู่ที่การออกแบบ คุณสามารถตั้งค่าคุณสมบัติที่เลือกใน SelectedItem ได้ แต่จะถูกละเว้นโดยสิ้นเชิงหากคุณสำรวจรายการด้วย GetEnumerator () (หรือถ้า Mvc ทำเพื่อคุณ) Mvc จะสร้าง SelectListItems ใหม่แทน

คุณต้องใช้ SelectList ctor กับ SelectListItem [], Text-Name, Value-Name และ SelectedValue โปรดทราบว่าจะส่งเป็น SelectedValue ค่าของ SelectListItem ซึ่งคุณต้องการให้เลือกไม่ใช่ SelectListItem เอง! ตัวอย่าง:

SelectList sl = new SelectList( new[]{
  new SelectListItem{ Text="one", Value="1"},
  new SelectListItem{ Text="two", Value="2"},
  new SelectListItem{ Text="three", Value="3"}
}, "Text", "Value", "2" );

(ไม่ได้ทดสอบ แต่ฉันมีปัญหาเดียวกัน)

จากนั้นตัวเลือกที่ 2 จะได้รับแอตทริบิวต์ selected = "selected" ดูเหมือน DataSets เก่าดี ;-)


11

นี่คือตัวเลือก:

myViewData.PageOptionsDropDown = new[] 
{
 new SelectListItem { Text = "10", Value = "10" },
 new SelectListItem { Text = "15", Value = "15", Selected = true }
 new SelectListItem { Text = "25", Value = "25" },
 new SelectListItem { Text = "50", Value = "50" },
 new SelectListItem { Text = "100", Value = "100" },
 new SelectListItem { Text = "1000", Value = "1000" },
}

SelectListItem ใหม่ {Selected = true, Text = "15", Value = "15"} สำหรับค่าที่เลือก
Cadoo

อ๊ะใช่ลืมใส่คุณสมบัติ 'ที่เลือก' ขอบคุณ Cadoo =)
murki

10

หากนั่นคือทั้งหมดที่คุณต้องการทำเพียงแค่ประกาศอาร์เรย์เป็นสตริงจะแก้ไขปัญหารายการที่เลือก:

myViewData.PageOptionsDropDown = 
   new SelectList(new string[] {"10", "15", "25", "50", "100", "1000"}, "15");

7

ง่ายมากที่จะทำให้ SelectList และ SelectedValue ทำงานร่วมกันแม้ว่าคุณสมบัติของคุณจะไม่ใช่วัตถุธรรมดา ๆ เช่นค่า Int, String หรือ Double

ตัวอย่าง:

สมมติว่าวัตถุภูมิภาคของเราเป็นดังนี้:

public class Region {
     public Guid ID { get; set; }
     public Guid Name { get; set; }
}

และโมเดลมุมมองของคุณมีลักษณะดังนี้:

public class ContactViewModel {
     public DateTime Date { get; set; }
     public Region Region { get; set; }
     public List<Region> Regions { get; set; }
}

คุณสามารถมีรหัสด้านล่าง:

@Html.DropDownListFor(x => x.Region, new SelectList(Model.Regions, "ID", "Name")) 

เฉพาะในกรณีที่คุณแทนที่เมธอด ToString ของ Region object เป็นบางอย่างเช่น:

public class Region {
     public Guid ID { get; set; }
     public Guid Name { get; set; }

     public override string ToString()
     {
         return ID.ToString();
     }
}

สิ่งนี้มีการรับประกัน 100% ในการทำงาน

แต่ฉันเชื่อจริงๆว่าวิธีที่ดีที่สุดในการทำให้ SelectList ทำงานได้ 100% ในวงจรทั้งหมดคือการใช้เมธอด Equals เพื่อทดสอบค่าคุณสมบัติ DropDownList หรือ ListBox เทียบกับแต่ละรายการในการรวบรวมรายการ


5

ดูเหมือนว่าหากคุณมีมุมมองที่พิมพ์ผิดอย่างมากคุณจำเป็นต้องเปลี่ยน ID ของดรอปดาวน์เพื่อไม่ให้เป็นชื่อของคุณสมบัติในคลาสที่สืบทอดมา จากนั้นคุณต้องใส่ตรรกะบางอย่างในวิธีการแก้ไข (POST) ของคุณเพื่อดึงค่าที่เลือกออกจาก FORMCollection และใส่ลงในอินสแตนซ์ของคุณก่อนที่จะทำการเปลี่ยนแปลงของคุณ

นี่เป็นเรื่องแปลกเล็กน้อย แต่ฉันลองแล้วมันได้ผล

ดังนั้นหากชั้นเรียนของคุณมีช่องชื่อ CountryId พูดและคุณกำลังแสดงรายชื่อประเทศให้รายการแบบเลื่อนลงมี ID ของ CountryName แทนที่จะเป็น CountryId จากนั้นในโพสต์คุณสามารถทำบางอย่างกับ Collection ["CountryName"] .


1
ใช่ฉันมีปัญหาเดียวกันนี้ เพียงแค่เปลี่ยนชื่อก็ใช้ได้แล้ว ขอบคุณ!
davekaro

4

ฉันมีปัญหาเดียวกันแน่นอน วิธีแก้ก็ง่ายๆ เพียงแค่เปลี่ยนพารามิเตอร์ "name" ที่ส่งผ่านไปยังผู้ช่วย DropDownList เป็นสิ่งที่ไม่ตรงกับคุณสมบัติใด ๆ ที่มีอยู่ใน ViewModel ของคุณ อ่านเพิ่มเติมที่นี่: http://www.dotnetguy.co.uk/post/2009/06/25/net-mvc-selectlists-selected-value-does-not-get-set-in-the-view

ฉันอ้างถึง Dan Watson:

ใน MVC หากมุมมองถูกพิมพ์อย่างมากตัวเลือกที่เลือกของรายการที่เลือกจะถูกแทนที่และคุณสมบัติตัวเลือกที่เลือกที่ตั้งค่าบนตัวสร้างจะไม่ไปถึงมุมมองและตัวเลือกแรกในเมนูแบบเลื่อนลงจะถูกเลือกแทน (ทำไมยังคงเป็นปริศนาอยู่เล็กน้อย) .

ไชโย!


3

คำตอบทั้งหมดนี้ดูดี แต่ดูเหมือนว่าคอนโทรลเลอร์กำลังเตรียมข้อมูลสำหรับ View ในรูปแบบโครงสร้างที่รู้จักกันดีเทียบกับการให้มุมมองเพียงวนซ้ำ IEnumerable <> ที่ส่งผ่านโมเดลและสร้างรายการเลือกมาตรฐานจากนั้นปล่อยให้ DefaultModelBinder ส่งรายการที่เลือกกลับมาให้คุณผ่านพารามิเตอร์การดำเนินการ ใช่ไม่ทำไมไม่? แยกความกังวลใช่หรือไม่? ดูเหมือนจะแปลกที่มีคอนโทรลเลอร์ในการสร้างบางอย่างเพื่อให้ UI และดูเฉพาะ



2

ฉันเพิ่งวิ่งแบบนี้และไม่มีปัญหา

public class myViewDataObj
    {
        public SelectList PageOptionsDropDown { get; set; }
    }

public ActionResult About()
        {
            myViewDataObj myViewData = new myViewDataObj();
            myViewData.PageOptionsDropDown =
                  new SelectList(new[] { "10", "15", "25", "50", "100", "1000" }, "15");

            ViewData["myList"] = myViewData.PageOptionsDropDown;
            return View();
        }

และ

<%=Html.DropDownList("myList") %>

มันก็ใช้ได้เช่นกันถ้าคุณทำเช่นนี้

public ActionResult About()
        {
            myViewDataObj myViewData = new myViewDataObj();
            myViewData.PageOptionsDropDown =
                  new SelectList(new[] { "10", "15", "25", "50", "100", "1000" });

            ViewData["myListValues"] = myViewData.PageOptionsDropDown;
            ViewData["myList"] = "15";
            return View();
        }

และ

<%=Html.DropDownList("myList",(IEnumerable<SelectListItem>)ViewData["myListValues"]) %>

1

การใช้ตัวอย่างของคุณสิ่งนี้ได้ผลสำหรับฉัน:

ควบคุม:

ViewData["PageOptionsDropDown"] = new SelectList(new[] { "10", "15", "25", "50", "100", "1000" }, "15");

ดู:

<%= Html.DropDownList("PageOptionsDropDown")%>

ใช่ที่ทำงานให้ฉันด้วย ในกรณีของฉันรายการคือวัตถุโมเดลเอนทิตี Controller: ViewData ["หมวดหมู่"] = SelectList ใหม่ (db.Categories ToList (), "CategoryId", "CategoryName", "15"); View: Html.DropDownList ("CategoryId", (SelectList) ViewData ["Categories"], "--select--")
Junior Mayhé

1
MonthRepository monthRepository = new MonthRepository();
IQueryable<MonthEntity> entities = monthRepository.GetAllMonth();
List<MonthEntity> monthEntities = new List<MonthEntity>();

foreach(var r in entities)
{
    monthEntities.Add(r);
}

ViewData["Month"] = new SelectList(monthEntities, "MonthID", "Month", "Mars");

1

ฉันทำแบบนี้:

List<SelectListItem> list = new List<SelectListItem>{
new SelectListItem {Selected = true, Text = "Select", Value = "0"},
new SelectListItem {Selected = true, Text = "1", Value = "1"},
new SelectListItem {Selected = true, Text = "2", Value = "2"}
};
return list.ToArray();

ToArray () ดูแลปัญหา


1

หากคุณต้องการส่งข้อความแบบสุ่มไปยัง DropDownList ของคุณเช่น - เลือก -คุณสามารถทำได้ง่ายๆโดยใช้รหัสนี้:

@Html.DropDownListFor(x => x.CategoryId, new SelectList(Model.Categories, "Id", "Name"), "--Select--", new { @class = "form-control" })


0

ค่าที่เลือกในแบบจำลองจะใช้ประโยชน์แทนรายการเริ่มต้น (ยอมรับว่าไม่ได้อ่านทุกกระทู้)


0

ฉันจำวิธีการตั้งค่า mvc 1 ไม่ได้ แต่ดูเหมือนว่ามันต้องการให้รายการเลือกที่มีชื่อเหมือนกับฟิลด์ที่เป็นของมันด้วย ...

สิ่งที่ฉันพบตามที่ใครบางคนกล่าวไว้ข้างต้นก็คือรายการที่เลือกของฉันไม่ทำงานใน mvc2 เมื่อ ViewData ที่พวกเขาถูกส่งตามที่มีชื่อเหมือนกับฟิลด์

ตัวอย่างเช่น:

<%= Html.DropDownListFor((model => model.ForID), (SelectList)ViewData["ForName"]) %>

ทำงานเมื่อ

<%= Html.DropDownListFor((model => model.ForID), (SelectList)ViewData["ForID"]) %>

ไม่ทำงานเนื่องจากชื่อ ViewData "ForID" มีชื่อเหมือนกับฟิลด์ที่ใช้งานได้


0

คำอธิบายที่เป็นไปได้คือค่า selectlist ที่คุณผูกไว้ไม่ใช่สตริง

ในตัวอย่างนั้นพารามิเตอร์ 'PageOptionsDropDown' เป็นสตริงในโมเดลของคุณหรือไม่? เพราะถ้าไม่ใช่ค่าที่เลือกในรายการจะไม่แสดง


0

ถ้าคุณดูในซอร์สโค้ดสำหรับ MVC 2 ที่เมธอดส่วนขยาย Html.DropDownList จะไม่ตรวจสอบคุณสมบัติ SelectList คลาส SelectedValue มันจะพยายามจับคู่กับโมเดลของคุณเท่านั้น

ทั้งหมดข้างต้นเป็นรูปแบบต่างๆในธีมกล่าวคือคุณจะส่งข้อมูลจำนวนมากไปยังมุมมองสำหรับรายการแบบเลื่อนลงได้อย่างไรและทุกอย่างดีพอ ๆ กัน (มากหรือน้อย)

ปัญหาอยู่ที่มุมมอง สร้างเมธอดส่วนขยาย DropDownList ของคุณเองที่สอดคล้องกับค่าที่คุณตั้งไว้หรือทำซ้ำด้วยมือ สิ่งที่ดีที่สุดสำหรับคุณ


@Franz Antesberger พูดในสิ่งเดียวกันมาก
Simon Halsey

0

หากคุณมีคอลเล็กชันในโมเดลของคุณและมุมมองของคุณเป็นประเภทที่ชัดเจนรูปแบบบางส่วนจะใช้ได้

@Html.DropDownListFor(x => x.RegionID, 
    new SelectList(Model.Regions,"RegionID", "RegionName", Model.RegionID))

-หรือ-

@Html.DropDownList("RegionID", 
    new SelectList(Model.Regions, "RegionID", "RegionName", Model.RegionID))
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.