ASP.NET MVC Html.DropDownList SelectedValue

103

Saya telah mencoba ini adalah RC1 dan kemudian meningkatkan ke RC2 yang tidak menyelesaikan masalah.

// in my controller
ViewData["UserId"] = new SelectList(
    users, 
    "UserId", 
    "DisplayName", 
    selectedUserId.Value); // this has a value

hasil: properti SelectedValue disetel pada objek

// in my view
<%=Html.DropDownList("UserId", (SelectList)ViewData["UserId"])%>

hasil: semua opsi yang diharapkan diberikan ke klien, tetapi atribut yang dipilih tidak disetel. Item di SelectedValue ada di dalam daftar, tetapi item pertama dalam daftar selalu default untuk dipilih.

Bagaimana saya harus melakukan ini?

Pembaruan Berkat jawaban John Feminella, saya mengetahui apa masalahnya. "UserId" adalah properti dalam Model my View sangat diketik. Saat Html.DropDownList ("UserId" diubah ke nama lain selain "UserId", nilai yang dipilih akan ditampilkan dengan benar.

Ini menghasilkan nilai yang tidak terikat ke model.

blu
sumber
Apakah Anda yakin bahwa nilainya ada dalam daftar?
John Sheehan
Masalah masih ada dalam Rilis 1 dari ASP.NET MVC
Mathias F
Apa yang selectedUserId !?
fulvio
Bagaimana Anda bisa mengikat nilai pada update lalu jika nama input Anda tidak sama dengan properti Anda?
ryudice

Jawaban:

68

Beginilah cara saya memperbaiki masalah ini:

Saya memiliki yang berikut ini:

Pengontrol:

ViewData["DealerTypes"] = Helper.SetSelectedValue(listOfValues, selectedValue) ;

Melihat

<%=Html.DropDownList("DealerTypes", ViewData["DealerTypes"] as SelectList)%>

Diubah oleh yang berikut:

Melihat

<%=Html.DropDownList("DealerTypesDD", ViewData["DealerTypes"] as SelectList)%>

Tampaknya DropDown tidak boleh memiliki nama yang sama memiliki nama ViewData: S aneh tetapi berhasil.

Sanchitos
sumber
19
+1 untuk "DropDown tidak boleh memiliki nama yang sama memiliki nama ViewData" Terima kasih besar
Daniel Dyson
Terima kasih!!! Anda baru saja memecahkan masalah saya setelah berjam-jam bertanya-tanya mengapa ini tidak berhasil :)
Jen
1
Ini berfungsi untuk nilai yang dipilih, tetapi masalah muncul saat Anda mencoba memperbarui "DealerTypes" di db karena DropDownList sekarang terikat ke "DealerTypesDD" yang tidak ada dalam model. Solusinya adalah dengan menambahkan bidang tersembunyi dan htmlAttributes ke DropDownList: <input type = "hidden" name = "DealerTypes" id = "DealerTypes" value = "" /> <% = Html.DropDownList ("DealerTypesDD", ViewData [ "DealerTypes"] sebagai SelectList, baru {@onchange = "DealerTypes.value = this.value"})%>
Zim
3
Anda lebih baik menambahkan 'DS' ke nama viewdata, sehingga tidak merusak pengikatan model ...
noocyte
1
Apa apaan! Ini tidak diperbaiki di MVC5 ??? Sebagai trik lain yang disebutkan oleh @Paul Hatcher, salin id yang dipilih ke ViewData ["DealerTypes"].
jsgoupil
51

Coba ini:

public class Person {
    public int Id { get; set; }
    public string Name { get; set; }
}

Lalu:

var list = new[] {   
    new Person { Id = 1, Name = "Name1" }, 
    new Person { Id = 2, Name = "Name2" }, 
    new Person { Id = 3, Name = "Name3" } 
};

var selectList = new SelectList(list, "Id", "Name", 2);
ViewData["People"] = selectList;

Html.DropDownList("PeopleClass", (SelectList)ViewData["People"])

Dengan MVC RC2, saya mendapatkan:

<select id="PeopleClass" name="PeopleClass">
    <option value="1">Name1</option>
    <option selected="selected" value="2">Name2</option>
    <option value="3">Name3</option>
</select>
John Feminella
sumber
Ini sangat membantu dalam melacak penyebabnya. Saya telah memperbarui pertanyaan saya untuk mencerminkan tambahan.
blu
model pertama? kedua dalam pengontrol? dan ketiga dalam tampilan itu jelas, tapi 2 yang pertama .. ???
rr
Jawaban bagus, tetapi bukankah lebih baik menggunakan ViewModel?
Jess
@ Jess: Saya menulis jawaban ini pada Maret 2009, lebih dari 5 tahun yang lalu. Waktu telah berubah! Jangan ragu untuk memperbarui. :)
John Feminella
5

Anda masih dapat menamai DropDown sebagai "UserId" dan masih memiliki pengikatan model yang berfungsi dengan benar untuk Anda.

Satu-satunya persyaratan agar ini berfungsi adalah bahwa kunci ViewData yang berisi SelectList tidak memiliki nama yang sama dengan properti Model yang ingin Anda ikat. Dalam kasus khusus Anda, ini adalah:

// in my controller
ViewData["Users"] = new SelectList(
    users, 
    "UserId", 
    "DisplayName", 
    selectedUserId.Value); // this has a value

// in my view
<%=Html.DropDownList("UserId", (SelectList)ViewData["Users"])%>

Ini akan menghasilkan elemen pilih bernama UserId, yang memiliki nama yang sama dengan properti UserId dalam model Anda dan oleh karena itu pengikat model akan menyetelnya dengan nilai yang dipilih dalam elemen pilih html yang dihasilkan oleh helper Html.DropDownList.

Saya tidak yakin mengapa konstruktor Html.DropDownList tertentu tidak akan memilih nilai yang ditentukan dalam SelectList saat Anda meletakkan daftar pilih di ViewData dengan kunci yang sama dengan nama properti. Saya menduga ini ada hubungannya dengan bagaimana helper DropDownList digunakan dalam skenario lain, di mana konvensi adalah bahwa Anda memiliki SelectList di ViewData dengan nama yang sama dengan properti dalam model Anda. Ini akan bekerja dengan benar:

// in my controller
ViewData["UserId"] = new SelectList(
    users, 
    "UserId", 
    "DisplayName", 
    selectedUserId.Value); // this has a value

// in my view
<%=Html.DropDownList("UserId")%>
Rui
sumber
Terima kasih banyak sobat, di atas semua jawaban ini berhasil untuk saya, tidak tahu mengapa tetapi berhasil
Lamin Sanneh
Akhirnya! Setelah berjam-jam mencoba, akhirnya saya menemukan "satu-satunya persyaratan" Anda. Itu berhasil.
SteveCav
2

Jika menurut kami ini bukan bug yang harus diperbaiki tim, sebaiknya MSDN memperbaiki dokumen tersebut. Yang membingungkan sebenarnya berasal dari dokumen buruk ini. Di MSDN , ini menjelaskan nama parameter sebagai,

Type: System.String
The name of the form field to return.

Ini hanya berarti html terakhir yang dihasilkannya akan menggunakan parameter itu sebagai nama input pemilihan. Tapi, sebenarnya artinya lebih dari itu.

Saya kira perancang berasumsi bahwa pengguna akan menggunakan model tampilan untuk menampilkan daftar tarik-turun, juga akan menggunakan pos kembali ke model tampilan yang sama . Tetapi dalam banyak kasus, kami tidak benar-benar mengikuti asumsi itu.

Gunakan contoh di atas,

public class Person {
    public int Id { get; set; }
    public string Name { get; set; }
}

Jika kita mengikuti asumsinya, kita harus mendefinisikan model tampilan untuk tampilan terkait dropdownlist ini

public class PersonsSelectViewModel{
    public string SelectedPersonId,
    public List<SelectListItem> Persons;
}

Karena ketika memposting kembali, hanya nilai yang dipilih yang akan memposting kembali, jadi nilai yang dipilih harus diposting kembali ke properti model SelectedPersonId, yang berarti nama parameter pertama Html.DropDownList harus 'SelectedPersonId'. Jadi, desainer berpikir bahwa saat menampilkan tampilan model dalam tampilan, properti model SelectedPersonId harus menyimpan nilai default dari daftar dropdown tersebut. Meskipun List <SelectListItem> Persons Anda telah menyetel flag yang Dipilih untuk menunjukkan mana yang dipilih / default, tml.DropDownList akan benar-benar mengabaikannya dan membangun ulang IEnumerable <SelectListItem> itu sendiri dan menyetel item default / yang dipilih berdasarkan namanya.

Berikut adalah kode dari asp.net mvc

private static MvcHtmlString SelectInternal(this HtmlHelper htmlHelper, ModelMetadata metadata,
            string optionLabel, string name, IEnumerable<SelectListItem> selectList, bool allowMultiple,
            IDictionary<string, object> htmlAttributes)
{
    ...

    bool usedViewData = false;

    // If we got a null selectList, try to use ViewData to get the list of items.
    if (selectList == null)
    {
        selectList = htmlHelper.GetSelectData(name);
        usedViewData = true;
    }

    object defaultValue = (allowMultiple) ? htmlHelper.GetModelStateValue(fullName, typeof(string[])) : htmlHelper.GetModelStateValue(fullName, typeof(string));

    // If we haven't already used ViewData to get the entire list of items then we need to
    // use the ViewData-supplied value before using the parameter-supplied value.
    if (defaultValue == null && !String.IsNullOrEmpty(name))
    {
        if (!usedViewData)
        {
            defaultValue = htmlHelper.ViewData.Eval(name);
        }
        else if (metadata != null)
        {
            defaultValue = metadata.Model;
        }
    }

    if (defaultValue != null)
    {
        selectList = GetSelectListWithDefaultValue(selectList, defaultValue, allowMultiple);
    }

    ...

    return tagBuilder.ToMvcHtmlString(TagRenderMode.Normal);
}

Jadi, kode sebenarnya melangkah lebih jauh, tidak hanya mencoba mencari nama di model, tetapi juga di viewdata, segera setelah menemukannya, ia akan membangun kembali selectList dan mengabaikan Selected asli Anda.

Masalahnya adalah, dalam banyak kasus, kami tidak benar-benar menggunakannya. kami hanya ingin memasukkan selectList dengan satu / beberapa item Selected set true.

Tentu saja solusinya sederhana, gunakan nama yang tidak ada di model atau di viewdata. Jika tidak dapat menemukan kecocokan, itu akan menggunakan selectList asli dan Selected asli akan berpengaruh.

Tapi saya masih berpikir MVC harus memperbaikinya dengan menambahkan satu syarat lagi

if ((defaultValue != null) && (!selectList.Any(i=>i.Selected)))
{
    selectList = GetSelectListWithDefaultValue(selectList, defaultValue, allowMultiple);
}

Karena, jika selectList asli sudah memiliki satu Selected, mengapa Anda mengabaikannya?

Hanya pikiranku.

liuhongbo
sumber
Ini benar-benar penjelasan terbaik yang pernah saya baca sejauh ini. Menyelamatkan saya dari banyak sakit kepala. Yang harus saya lakukan hanyalah menyetel nilai properti viewmodel dan berhasil. Terima kasih.
Moses Machua
2

Kode di posting MVC 3 sebelumnya tidak berfungsi tetapi ini adalah awal yang baik. Saya akan memperbaikinya. Saya telah menguji kode ini dan bekerja di MVC 3 Razor C # Kode ini menggunakan pola ViewModel untuk mengisi properti yang mengembalikan a List<SelectListItem>.

Kelas Model

public class Product
{
    public string Name { get; set; }
    public decimal Price { get; set; }
}

Kelas ViewModel

using System.Web.Mvc;

public class ProductListviewModel
{
    public List<SelectListItem> Products { get; set; }
}

Metode Pengontrol

public ViewResult List()
{
    var productList = new List<SelectListItem>();

    foreach (Product p in Products)
    {
        productList.Add(new SelectListItem
        {
            Value = p.ProductId.ToString(),
            Text = "Product: " + p.Name + " " + p.Price.ToString(),
            // To set the selected item use the following code 
            // Note: you should not set every item to selected
            Selected = true
        });
    }

    ProductListViewModel productListVM = new ProductListViewModeld();

    productListVM.Products = productList;

    return View(productListVM);
}

Pandangan

@model MvcApp.ViewModels.ProductListViewModel

@using (Html.BeginForm())
{
    @Html.DropDownList("Products", Model.Products)
}

Output HTML akan menjadi seperti

<select id="Products" name="Products">
    <option value="3">Product: Widget 10.00</option>
    <option value="4">Product: Gadget 5.95</option>
</select>

tergantung bagaimana Anda memformat keluaran. Saya harap ini membantu. Kode itu berfungsi.

wayne.blackmon
sumber
1
Ini tidak mengatur selectedopsi.
Jess
Untuk menyetel item yang dipilih menggunakan SelectListItem, setel properti Selected ke true.
wayne.blackmon
1

Ini tampaknya merupakan bug di kelas SelectExtensions karena hanya akan memeriksa ViewData daripada model untuk item yang dipilih. Jadi triknya adalah menyalin item yang dipilih dari model ke dalam koleksi ViewData di bawah nama properti.

Ini diambil dari jawaban yang saya berikan di forum MVC, saya juga punya jawaban yang lebih lengkap di postingan blog yang menggunakan atribut DropDownList Kazi ...

Diberikan model

public class ArticleType
{
   public Guid Id { get; set; }
   public string Description { get; set; }
}

public class Article
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public ArticleType { get; set; }
}

dan model tampilan dasar

public class ArticleModel
{
     public Guid Id { get; set; }
     public string Name { get; set; }

     [UIHint("DropDownList")]
     public Guid ArticleType { get; set; }
}

Kemudian kami menulis template editor DropDownList sebagai berikut ..

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<script runat="server">  
    IEnumerable<SelectListItem> GetSelectList()
    {
        var metaData = ViewData.ModelMetadata;
        if (metaData == null)
        {
            return null;
        }

        var selected = Model is SelectListItem ? ((SelectListItem) Model).Value : Model.ToString();
        ViewData[metaData.PropertyName] = selected;

        var key = metaData.PropertyName + "List";
        return (IEnumerable<SelectListItem>)ViewData[key];
    }
</script>
<%= Html.DropDownList(null, GetSelectList()) %>

Ini juga akan berfungsi jika Anda mengubah ArticleType dalam model tampilan ke SelectListItem, meskipun Anda harus menerapkan pengonversi tipe sesuai blog Kazi dan mendaftarkannya untuk memaksa pengikat memperlakukan ini sebagai tipe sederhana.

Di pengontrol Anda, kami kemudian memiliki ...

public ArticleController 
{
     ...
     public ActionResult Edit(int id)
     {
          var entity = repository.FindOne<Article>(id);
          var model = builder.Convert<ArticleModel>(entity);

          var types = repository.FindAll<ArticleTypes>();
          ViewData["ArticleTypeList"] = builder.Convert<SelectListItem>(types);

          return VIew(model);
     }
     ...
}
Paul Hatcher
sumber
Terima kasih atas jawabannya, saya harus memeriksanya.
blu
0

Masalahnya adalah bahwa dropbox tidak berfungsi sama dengan listbox, setidaknya seperti yang diharapkan oleh desain ASP.NET MVC2: Dropbox hanya mengizinkan nol atau satu nilai, karena listbox dapat memiliki pilihan beberapa nilai. Jadi, karena ketat dengan HTML, nilai itu tidak boleh ada dalam daftar opsi sebagai tanda "dipilih", tetapi di masukan itu sendiri.

Lihat contoh berikut:

<select id="combo" name="combo" value="id2">
  <option value="id1">This is option 1</option>
  <option value="id2" selected="selected">This is option 2</option>
  <option value="id3">This is option 3</option>
</select>

<select id="listbox" name="listbox" multiple>
  <option value="id1">This is option 1</option>
  <option value="id2" selected="selected">This is option 2</option>
  <option value="id3">This is option 3</option>
</select>

Combo memiliki opsi yang dipilih, tetapi juga memiliki kumpulan atribut nilainya . Jadi, jika Anda ingin ASP.NET MVC2 merender dropbox dan juga memilih nilai tertentu (misalnya, nilai default, dll.), Anda harus memberinya nilai dalam rendering, seperti ini:

// in my view             
<%=Html.DropDownList("UserId", selectListItems /* (SelectList)ViewData["UserId"]*/, new { @Value = selectedUser.Id } /* Your selected value as an additional HTML attribute */)%>
dalotodo.dll
sumber
0

Di ASP.NET MVC 3 Anda cukup menambahkan daftar Anda ke ViewData ...

var options = new List<SelectListItem>();

options.Add(new SelectListItem { Value = "1", Text = "1" });
options.Add(new SelectListItem { Value = "2", Text = "2" });
options.Add(new SelectListItem { Value = "3", Text = "3", Selected = true });

ViewData["options"] = options;

... dan kemudian rujuk dengan nama di tampilan pisau cukur Anda ...

@Html.DropDownList("options")

Anda tidak perlu "menggunakan" daftar secara manual di panggilan DropDownList. Melakukannya dengan cara ini dengan benar mengatur nilai yang dipilih untuk saya juga.

Penolakan:

  1. Belum mencoba ini dengan mesin tampilan formulir web, tetapi seharusnya berfungsi juga.
  2. Saya belum menguji ini di v1 dan v2, tetapi mungkin berhasil.
John Bubriski
sumber
0

Saya berhasil mendapatkan hasil yang diinginkan, tetapi dengan pendekatan yang sedikit berbeda. Dalam Dropdownlist saya menggunakan Model dan kemudian mereferensikannya. Tidak yakin apakah ini yang Anda cari.

@Html.DropDownList("Example", new SelectList(Model.FeeStructures, "Id", "NameOfFeeStructure", Model.Matters.FeeStructures))

Model.Matters.FeeStructures di atas adalah my id, yang bisa menjadi nilai Anda dari item yang harus dipilih.

Jukes
sumber