Using inline editing from a kendo grid (v 2017.3.913), the editor template used for the dropdown is not using the property id to set the selected value in the list (or it's another issue but related).
I tried several solutions from like-kind SO questions but nothings has yielded the expected results.
kendo grid
//ParentOrganization is the target property
#(Html.Kendo().Grid<OrganizationGridViewModel>()
.Name("organizationGrid")
.Columns(columns =>
{
columns.Bound(o => o.Id).Width(150).Hidden(true);
columns.Bound(o => o.Name);
columns.Bound(o => o.ParentOrganization).ClientTemplate("#= (ParentOrganization.Id == 0) ? ' ' : ParentOrganization.Name #").EditorTemplateName("ParentOrganization");
columns.Bound(o => o.OrganizationTypeDescription).Width(165);
columns.Command(command =>
{
command.Edit().Text(" ").HtmlAttributes(new { title = "Edit Organization" });
command.Destroy().Text(" ").HtmlAttributes(new { title = "Delete Organization" });
}).Width(250);
})
.ToolBar(toolbar => toolbar.Create().Text("New"))
.Editable(editable => editable.Mode(GridEditMode.InLine).ConfirmDelete("Are you sure you want to delete this organization?")
.DisplayDeleteConfirmation("Organization deleted"))
...
Since the bound column is an navigational object (versus a primitive type) I use the [UIHint] in the viewmodel to point to an editor template, so that the object is mapped properly.
viewmodel used in the grid
public class OrganizationGridViewModel
{
...
// NOTE: the Organization object has "Id" and "Name" properties
[UIHint("ParentOrganization")]
public Organization ParentOrganization { get; set; }
}
editor template
#(Html.Kendo().DropDownList()
.Name("ParentOrganization")
.DataTextField("Text")
.DataValueField("Value")
.BindTo((IEnumerable) ViewData["OrganizationSelectList"])
)
And finally, the data used by the dropdownlist:
var orgSelectList = organizations.Select(n => new SelectListItem
{
Text = n.Name,
Value = n.Id.ToString()
}).ToList();
ViewData["OrganizationSelectList"] = new SelectList(orgSelectList, "Value", "Text");
NOTE
I also tried creating a SelectList using "Id" & "Name" (propagated the change to the editor as well - replaced "Value" & "Text") so it would align with the ParentOrganization object but that ended up producing "undefined" list items.
orgSelectItems.AddRange(organizations.Select( n => new BaseSelectItem
{
Id = n.Id,
Name = n.Name
}));
ViewData["OrganizationSelectList"] = new SelectList(orgSelectList, "Id", "Name");
This is how im getting data into and out of my dropdowns for Kendo
#(Html.Kendo().DropDownList()
.Name("showProcessed")
.DataTextField("OptionText")
.DataValueField("ViewOption")
.AutoBind(true)
.SelectedIndex(2)
.Events(e => e.Change("fe_DiaryItem.processedChange"))
.HtmlAttributes(new { style = "width: 250px;" })
.DataSource(ds =>
{
ds.Read("DiaryGridViewOptions", "ControllerName");
})
)
In this instance I populate the object with the DataSource, and select the index using .SelectedIndex(x).
I have other examples of how to set the index if you need but this is working production code.
----Edit----
#{
var idxDst = 0;
if (Model.DiaryTimeSlot != null && Model.DiaryTimeSlotSelectedId > 0)
{
idxDst = Model.DiaryTimeSlot.IndexOf(Model.DiaryTimeSlot.First(x => x.DiaryTimeSlotID == Model.DiaryTimeSlotSelectedId));
}
}
#(Html.Kendo().DropDownList()
.Name("DiaryTimeSlot")
.DataTextField("Description")
.DataValueField("DiaryTimeSlotID")
.SelectedIndex(idxDst)
.BindTo(Model.DiaryTimeSlot)
.DataSource(ds =>
{
ds.Read("DiaryTimeSlotOptions", "ControllerName");
})
)
It appears that [Kendo or MVC helpers themselves] don't like you using "proper" [Domain] objects - appears to confuse the binding. I believe the root cause is the property names are the same (Id & Name) and need to be different. I was using a domain object Organization as the property's type. I created another viewmodel to represent the organization and used different property names:
new viewmodel to represent the org
instead of using "Id" & "Name" as the mapped text and value properties I'm using the following "ParentOrganization-x" properties:
public class ParentOrganizationViewModel
{
public int? ParentOrganizationId { get; set; }
public string ParentOrganizationName { get; set; }
}
So an update to the grid viewmodel will reflect the new org viewmodel:
public class OrganizationGridViewModel
{
...
[UIHint("ParentOrganization")]
public ParentOrganizationViewModel ParentOrganization { get; set; }
}
Also, instead of returning a SelectList as the datasource to the dropdown, it's a straight viewlmodel list:
var orgSelectList = organizations.Select(n => new ParentOrganizationViewModel()
{
ParentOrganizationName = n.Name,
ParentOrganizationId = n.Id
}).ToList();
ViewData["OrganizationSelectList"] = orgSelectList;
The final changes are in the editor template, to change the DataTextField and DataValueField properties match the org viewmodel:
#(Html.Kendo().DropDownList()
.Name("ParentOrganization")
.DataTextField("ParentOrganizationName")
.DataValueField("ParentOrganizationId")
.AutoBind(true)
.ValuePrimitive(true)
.BindTo((IEnumerable) ViewData["OrganizationSelectList"])
)
Related
I'm trying to use a Kendo grid with inline editing but my data does not change on pressing update. Other columns have no problem, but the drop down data is not updated.
My model class is:
public class Validation
{
public string ParentParameterName { get; set; }
public string ParameterName { get; set; }
public string ParameterTitle { get; set; }
[UIHint("DataTypeList")]
public string DataType { get; set; }
[UIHint("EvetHyir")]
public string Required { get; set; }
public List<Validation> Value { get; set; }
}
My grid is:
#(Html.Kendo().Grid<Validation>()
.Name("keyJsonGrid")
.Columns(columns =>
{
columns.Bound(model => model.ParentParameterName).Title("Ana parametre ünvanı");
columns.Bound(model => model.ParameterTitle).Title("Parametre ünvanı");
columns.Bound(model => model.ParameterName).Title("Parametre Adı");
//columns.Bound(foo => foo.DataType).Title("TİP").EditorTemplateName("DataType").Sortable(false);
columns.Bound(p => p.DataType).Sortable(false).Width(180).EditorTemplateName("DataTypeList");
columns.Command(command => { command.Edit().Text("Düzenle"); command.Destroy().Text("Sil"); }).Width(250);
})
.Resizable(builder => builder.Columns(true))
.ToolBar(toolbar => toolbar.Create().Text("Yeni Ekle"))
.Editable(editable => editable
.Mode(GridEditMode.InLine)
.ConfirmDelete("Silinmesine emin misiniz?")
.DisplayDeleteConfirmation("Silinmesine emin misiniz?")
)
.Pageable(pageable => pageable
.Refresh(true)
.PageSizes(new int[] { 10, 25, 50, 75, 100 })
)
.Sortable(x => x.SortMode(GridSortMode.MultipleColumn))
.DataSource(dataSource => dataSource
.Ajax()
.Read(read => read.Action("GetJsonKeyList", "Key", new { KeyId = Model }))
.PageSize(25)
)
)
My dropdown is populated from an enum:
#(Html.Kendo().DropDownList()
// The name of the widget has to be the same as the name of the property.
.Name("DataType")
// The value of the drop-down is taken from the EmployeeID property.
.DataValueField("Text")
.DataTextField("Text")
.AutoBind(true)
// The text of the items is taken from the EmployeeName property.
.ValuePrimitive(true)
// A list of all employees which is populated in the controller.
.BindTo((System.Collections.IEnumerable)ViewData["DataTypes"])
)
Dropdown data population code:
KeyJsonDTO.DataType x = KeyJsonDTO.DataType.Integer;
ViewData["DataTypes"] = EnumToSelectList(x.GetType());
static List<SelectListItem> EnumToSelectList(Type enumType)
{
return Enum.GetValues(enumType)
.Cast<int>()
.Select(i => new SelectListItem
{
Value = i.ToString(),
Text = Enum.GetName(enumType, i),
})
.ToList();
}
When I press the "Edit" button, the dropdown does not show correct data, and when I press update data, it does not update.
I doubt you are actually using the dropdown you created. "DataType" is not the name of the field. It is the name of the editor template you save in the file system. You can use controls on page but as far as i know, only if it's a javascript grid. You need to make an editor template in the appropriate folder and change the definition of the control to be an dropdownfor(m => m). Then you don't have to name it.
Hi I have a problem with DropDownListFor on the Edit view.
Basically I'm using a partial view which contains my form and in my Edit and Create view I call this partial view.
I have around 5 similiar DropdownlistFor and these work well on create action but in edit doesn't, mainly i'm not getting (unable) to set the selected value.
In my Edit Action (GET), I fill my property ViewModel if the true object has the property filled.
if(icb.BAOfficer != null)
editICB.BAOfficer = icb.BAOfficer;
List<Staff> staffs = _fireService.GetAllStaffs().ToList();
staffs.Insert(0, new Staff { StaffId = -1, Name = "" });
editICB.BAOfficers = staffs;
return View(editICB);
This is how I'm filling my drop down and how I'm trying to set the selected value.
#Html.DropDownListFor(model => model.BAOfficerSelected, new SelectList(Model.BAOfficers, "StaffId", "Name", (Model.BAOfficer!= null ? Model.BAOfficer.StaffId:-1)), new { #class = "rounded indent" })
#Html.ValidationMessageFor(model => model.BAOfficer.StaffId)
I solve the problem setting a value to my model.BAOfficerSelected in Edit Action, this was the (easy) secret.
I need the first item like a empty option because is not a required information, but on the edit view if has value I need to set it as selected option.
In the end, it was my code.
My Model
public int BAOfficerSelected { get; set; }
public SelectList BAOfficers { get; set; }`
My Controller Create/Edit Action
if (icb.BAOfficer != null) // only for edit action
editICB.BAOfficerSelected = icb.BAOfficer.StaffId; //this will set the selected value like a mapping
//for Edit and Create
List<Staff> staffs = _fireService.GetAllStaffs().ToList();
staffs.Insert(0, new Staff { StaffId = -1, Name = "" });
editICB.BAOfficers = new SelectList(staffs, "StaffId", "Name");
return View(editICB);`
My View
#Html.DropDownListFor(model => model.BAOfficerSelected, Model.BAOfficers, new { #class = "rounded indent" })
I hope this can help others.
The best and cleanest way of doing this is setting the selected value in server side, in the SelectList object.
So, if your BAOfficerSelected is nullable... it is all simpler: You don't need to rely in adding a dummy item to hold the -1 for not selected value.
Instead, you do it this way:
List<Staff> staffs = _fireService.GetAllStaffs().ToList();
editICB.BAOfficers = new SelectList(staffs, "StaffId", "Name", editICB.BAOfficer != null ? editICB.BAOfficer.StaffId : null);
Of course, the BAOfficers need to be changed type from List<Staff> to SelectList.
Then, in your partial view you do:
#Html.DropDownListFor(model => model.BAOfficerSelected, Model.BAOfficers, "Select one...", new { #class = "rounded indent" })
Adding the 3rd parameter is needed to indicate that the default value (if nothing is selected) is that text.
Instead of using a SelectList, I often find it works better to use a List<SelectListItem>.
Further, I usually use an EditorTemplate for my dropdowns to keep my views clean.
So if my select list returns List<SelectListItem>:
public List<SelectListItem> BAOfficers { get; set };
You can set it up like this:
model.BAOfficers = staffs.Select(staff =>
new SelectListItem { Text = staff.Name, Value = staff.StaffId }).ToList();
Then in your EditorTemplate:
<!-- EditorTempaltes\DropDownList.cshtml -->
#model System.String
<p>
#Html.LabelFor(m => m):
#Html.DropDownListFor(m => m, new SelectList(
(List<SelectListItem>)ViewData["selectList"], "Value", "Text",
String.IsNullOrEmpty(Model) ? String.Empty : Model), String.Empty)
#Html.ValidationMessageFor(m => m)
</p>
And then in the view, just pass the SelectList into the EditorTemplate:
#Html.EditorFor(m => m.BAOfficerSelected, "DropDownList",
new { selectList = Model.BAOfficers() })
I met the same problem ,too.
According the article https://dotnetfiddle.net/PIGNLF which way gave a simple way to deal with this problem without two Models or more classes.enter link description here
here is my code
add model
public class NoteSelectLisModel
{
public string Value { get; set; }
public string Name { get; set; }
}
add Controller
public ActionResult Edit(int? _ID)
{
ViewBag.NoteState = new SelectList(new List<NoteSelectLisModel>()
{
new NoteSelectLisModel() {Value="1",Name="A)"},
new NoteSelectLisModel() {Value="2",Name="B"},
new NoteSelectLisModel() {Value ="3",Name ="C"}
}, "Value", "Name", 1);
Table ut = _db.Tables.Find(_ID);
if (ut == null)
{
return HttpNotFound();
}
else
{
return View(ut);
}
}
add View .cshtml
#Html.DropDownListFor(m => m.NOTE, (IEnumerable<SelectListItem>)ViewBag.NoteState, "No Selected")
The edit's Model is the same and the dropdownlist passed by View.bag
I have a Kendo MVC grid that contains a nullable property (short) that is bound as a foreign key and uses a dropdown list as an editor template. I am also using inline editing.
When the property value is null, the dropdown list selected value does not get set into the grid cell after the update button is clicked. This works fine if incell editing is used. I am looking for a workaround that will solve my problem. I am including a stripped down version of my code below
Everything works if the nullable value is set to a non-null value.
GRID
#(Html.Kendo().Grid<AssetViewModel>()
.Name("DealAssets")
.Columns(c =>
{
c.Bound(x => x.Name);
c.ForeignKey(x => x.AssetTypeID, (IEnumerable<SelectListItem>)ViewBag.AssetTypeList, "Value", "Text");
c.ForeignKey(x => x.SeniorityTypeID, seniorityTypeList, "Value", "Text").EditorTemplateName("GridNullableForeignKey");
c.ForeignKey(x => x.RateBaseID, rateBaseList, "Value", "Text").EditorTemplateName("GridNullableForeignKey"); ;
c.Command(m => { m.Edit(); m.Destroy(); });
})
.ToolBar(toolbar => toolbar.Create().Text("Add New Asset"))
.Editable(x => x.Mode(GridEditMode.InLine))
.DataSource(ds => ds
.Ajax()
.Model(model => model.Id(request => request.ID))
.Read(read => read.Action("ReadAssets", "Deal", new { id = Model.ID }))
.Create(create => create.Action("CreateAsset", "Deal", new { currentDealID = Model.ID }))
.Update(update => update.Action("UpdateAsset", "Deal"))
.Destroy(destroy => destroy.Action("DeleteAsset", "Deal"))
)
)
EDITOR TEMPLATE
#model short?
#{
var controlName = ViewData.TemplateInfo.GetFullHtmlFieldName("");
}
#(
Html.Kendo().DropDownListFor(m => m)
.Name(controlName)
.OptionLabel("- Please select -")
.BindTo((SelectList)ViewData[ViewData.TemplateInfo.GetFullHtmlFieldName("") + "_Data"])
)
UPDATE ACTION
public ActionResult UpdateAsset([DataSourceRequest] DataSourceRequest request, int ID)
{
var dealAsset = DataContext.DealAssets.SingleOrDefault(o => o.ID == ID);
if (dealAsset != null)
{
if (TryUpdateModel(dealAsset.Asset, new[] {"Name","AssetTypeID","SeniorityTypeID","RateBaseID" }))
{
DataContext.SaveChanges();
}
}
return Json(new[] { new AssetViewModel(dealAsset) }.ToDataSourceResult(request, ModelState), JsonRequestBehavior.AllowGet);
}
Telerik just recently added a new HTML attribute, data_value_primitive, to their selectlist that addresses the issue above. The new attribute should be added in the foreign key editor template and set to true.
Html.Kendo().DropDownListFor(m => m)
.Name(controlName)
.OptionLabel("- Please select -")
.BindTo((SelectList)ViewData[ViewData.TemplateInfo.GetFullHtmlFieldName("") + "_Data"])
**.HtmlAttributes(new { data_value_primitive = true})**
This last section is a modification to the update method to account for the grid not passing back null properties when doing the ajax call. I think this has more to do with how the TryUpdateModel method works
...
if (TryUpdateModel(dealAsset.Asset, new[] {"Name","AssetTypeID","SeniorityTypeID","RateBaseID" }))
{
// If no property passed back then set it to null
var senorityTypeID = ValueProvider.GetValue("SeniorityTypeID");
if (senorityTypeID == null)
{
dealAsset.Asset.SeniorityTypeID = null;
} else {
dealAsset.Asset.SeniorityTypeID = (short)senorityTypeID.ConvertTo(typeof(short));
}
var rateBaseID = ValueProvider.GetValue("RateBaseID");
if (rateBaseID == null)
{
dealAsset.Asset.RateBaseID = null;
} else {
dealAsset.Asset.RateBaseID = (byte)rateBaseID.ConvertTo(typeof(byte));
}
DataContext.SaveChanges();
}
'''
I am getting a null value passed to my ajax .Update("_SaveAjaxEditing", "AptProfile") in my controller when using the dropdownlist client Edit Template.
property in my FormViewModel that my grid is bound to:
[UIHint("BuildingsGrid"), Required]
[DisplayName("Building ID")]
public int BuildingID
{
get;
set;
}).
Here is my view:
<%= Html.Telerik().Grid<PayRent.Models.AptProfileFormViewModel1>()
.Name("Profiles")
.DataKeys(dataKeys => dataKeys.Add(c => c.AptProfileID))
.ToolBar(commands => commands.Insert())
.DataBinding(binding =>
{
binding.Ajax()
.Select("GetProfiles", "AptProfile")
.Insert("_InsertAjaxEditing", "AptProfile")
.Update("_SaveAjaxEditing", "AptProfile")
.Delete("_DeleteAjaxEditing", "AptProfile");
})
.Columns(columns =>
{
columns.Bound(o => o.AptProfileID);
columns.Bound(o => o.BuildingID);
columns.Bound(o => o.AptID);
columns.Bound(o => o.AptRate);
columns.Bound(o => o.AptSize);
columns.Bound(o => o.MoveInDate);
columns.Command(s =>
{
s.Edit();
s.Delete();
});
})
.Editable(editing => editing.Mode(GridEditMode.InLine))
.ClientEvents(events => events.OnEdit("onEdit"))
.Pageable()
%>
</p>
<script type="text/javascript">
function onEdit(e) {
// $(e.form).find('#BuildingsGrid').data('tDropDownList').select(function (dataItem) {
// return dataItem.Text == e.dataItem['BuildingGrid'];
// });
}
</script>
My EditTemplate:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<%= Html.Telerik().DropDownList()
.Name("BuildingsGrid")
.BindTo(new SelectList((IEnumerable)ViewData["Buildings"], "BuildingID", "Name"))
%>)
Here is my Controller:
[AcceptVerbs(HttpVerbs.Post)]
//[CultureAwareAction]
[GridAction]
public ActionResult _SaveAjaxEditing(int id, int? BuildingGrid)
{
ApartmentProfileRepository repo = new ApartmentProfileRepository();
AptProfile profile = repo.Get(id);
TryUpdateModel(profile);
repo.Save();
return View(new GridModel(GetAllProfiles()));
}
If you want to keep everything Ajax-ified, you have do it without using the viewbag. My combobox is in a separate editor template. All you have to do is return the SelectList as a JsonResult. That said, I only recommended doing it that way if you expect the data in that combobox to change while the user is on the page, because it calls the server method every time the combo is opened.
In my example below, because the user can add a Category on the same page as they're selecting a Category, I need it to hit the server each time. But on other pages, I use server-side binding (via the ViewBag/ViewData) so that it only hits the server once.
My editor template:
#(Html.Telerik().ComboBox()
.Name("YourNameGoesHere")
.DataBinding(binding => binding.Ajax().Select("SelectCategoriesForComboBox","Shared")))
Then in the controller:
public EquipmentEntities db = new EquipmentEntities();
public List<SelectListItem> CategoryList
{
get
{
var m = db.Categories
.Select(e => new{ Id = e.Id, Name = e.Name })
.OrderBy(e => e.name);
List<SelectListItem> sl = new SelectListItem(m.ToList(), "Id", "Name").ToList();
//insert a blank item as the first entry
sl.Insert(0, (new SelectListItem { Text = "", Value = string.Empty }));
return sl;
}
}
[HttpPost]
public ActionResult SelectCategoryForComboBox()
{
return new JsonResult { Data = CategoryList };
}
Maybe I'm a little bit late, but hopefully it helps someone out.
First, you need to match up the name of your column in the view with the name of your edit template and controller action parameter. I don't think the int parameter needs to be nullable in the controller action.
Then in your controller action you need to set the ViewData["Buildings"] for the edit template; then select the current value in your profile object before returning the view.
e.g.
public ActionResult _SaveAjaxEditing(int id, int BuildingsGrid)
{
ApartmentProfileRepository repo = new ApartmentProfileRepository();
AptProfile profile = repo.Get(id);
// Save the building ID in the profile
profile.BuildingID = BuildingsGrid;
TryUpdateModel(profile);
repo.Save();
// Load the Building objects into the ViewData
ViewData["Buildings"] = GetBuildings();
return View(new GridModel(GetAllProfiles()));
}
Working on my first ASP.Net MVC2 web app recently, I came across some issues when I needed to select multiple values in a list box. I worked around it with some jQuery, but went ahead and put together some very simple code to demonstrate. I'm using EF for the model, with two entities - Customers and HelpDeskCalls:
Controller:
public ActionResult Edit(int id)
{
Customer currCustomer = ctx.Customers.Include("HelpDeskCalls").Where(c => c.ID == id).FirstOrDefault();
List<HelpDeskCall> currCustCalls = (ctx.HelpDeskCalls.Where(h => h.CustomerID == id)).ToList();
List<SelectListItem> currSelectItems = new List<SelectListItem>();
List<String> selectedValues = new List<string>();
foreach (HelpDeskCall currCall in currCustCalls)
{
bool isSelected = (currCall.ID % 2 == 0) ? true : false;
//Just select the IDs which are even numbers...
currSelectItems.Add(new SelectListItem() { Selected = isSelected, Text = currCall.CallTitle, Value = currCall.ID.ToString() });
//add the selected values into a separate list as well...
if (isSelected)
{
selectedValues.Add(currCall.ID.ToString());
}
}
ViewData["currCalls"] = (IEnumerable<SelectListItem>) currSelectItems;
ViewData["currSelected"] = (IEnumerable<String>) selectedValues;
return View("Edit", currCustomer);
}
View:
<div class="editor-field">
<%: Html.ListBoxFor(model => model.HelpDeskCalls, new MultiSelectList(Model.HelpDeskCalls, "ID", "CallTitle", (IEnumerable) ViewData["currSelected"]), new { size = "12" })%>
<%: Html.ListBoxFor(model => model.HelpDeskCalls, ViewData["currCalls"] as IEnumerable<SelectListItem>, new { size = "12"}) %>
<%: Html.ListBox("Model.HelpDeskCalls", new MultiSelectList(Model.HelpDeskCalls, "ID", "CallTitle", (IEnumerable)ViewData["currSelected"]), new { size = "12"}) %>
<%: Html.ValidationMessageFor(model => model.HelpDeskCalls) %>
</div>
For this sample, I'm just selecting HelpDeskCall.IDs which are even. I'm trying two different syntaxes for ListBoxFor: One uses an IEnumerable of values for selections, one using an IEnumerable of SelectListItems. By default, when I run this code, no selections are made to either ListBoxFor, but the non-strongly typed ListBox selects correctly.
I read this post on ASP.Net and this thread on SO, but no joy. In fact, if I add the override ToString() to my HelpDeskCall class (as suggested in the ASP.net thread) all values are selected, which isn't right either.
If someone could shed some light on how this should work (and what I'm missing or doing wrong), this then neophyte would be very grateful.
Here's an example illustrating the strongly typed version:
Model:
public class MyViewModel
{
public int[] SelectedItemIds { get; set; }
public MultiSelectList Items { get; set; }
}
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
// Preselect items with id 1 and 3
var selectedItemIds = new[] { 1, 3 };
var model = new MyViewModel
{
Items = new MultiSelectList(
new[]
{
// TODO: Fetch from your repository
new { Id = 1, Name = "item 1" },
new { Id = 2, Name = "item 2" },
new { Id = 3, Name = "item 3" },
},
"Id",
"Name",
selectedItemIds
)
};
return View(model);
}
}
View:
<%: Html.ListBoxFor(x => x.SelectedItemIds, Model.Items) %>
I don't know if this behaviour has changed in the RTM of MVC3 that I'm using, but it seems that selection and binding now works out of the box. The only catch is that the model should contain a property with the IDs, like that :
public class MyViewModel {
public int[] ItemIDs { get; set; }
}
Then the following in the view would work fine, both pre-selecting the correct values and binding correctly during post:
#Html.ListBoxFor(model => model.ItemIDs, (IEnumerable<SelectListItem>)(new[] {
new SelectListItem() { Value = "1", Text = "1" },
new SelectListItem() { Value = "2", Text = "2" }
}))
I have found better workaround. Usual way to preselect select list:
#Html.ListBoxFor(
model => model.Roles,
new MultiSelectList(db.Roles, "Id", "Name")
)
#Html.ValidationMessageFor(model => model.Roles)
Doesn't work.., never ever any option is selected, until:
public ActionResult Edit(int id)
{
var user = db.Users.Find(id);
// this is workaround for http://aspnet.codeplex.com/workitem/4932?ProjectName=aspnet
ViewData["Roles"] = user.Roles.Select(r => r.Id);
return View(user);
}
Selected Roles has to be stored in ViewData, to workaround nasty bug.
Another option is to take advantage of nameof, you could do something like this;
Html.ListBox(nameof(MainProjectViewModel.Projects), Model.Projects)