我的单选按钮看起来像这样
@foreach (ItemHasParts ihp in item.IHP)
{
Part part = db.Parts.Find(ihp.PartID);
string partID = part.ID.ToString();
<tr>
<td>
@part.PartIDLink
</td>
<td>
@Html.DisplayFor(modelPart => part.MFG_number)
</td>
<td>
@Html.DisplayFor(modelPart => part.Name)
</td>
<td>
@Html.RadioButton(partID, "Harvest")
</td>
<td>
@Html.RadioButton(partID, "Transfer")
</td>
<td>
@Html.RadioButton(partID, "Dispose")
</td>
</tr>
}
这是我的控制器方法
public ActionResult SpecialOrderSummary(JobOrder job, FormCollection form)
{
//list of parts that were chosen to be transferred
//list of parts that were chosen to be harvested
//list of parts that were chosen to be disposed
return RedirectToAction("Details", "JobOrders", new { id = job.ID });
}
它循环并为每个部分生成单选按钮。如何使控制器检索用户选择的每个单选按钮的值?
答案 0 :(得分:0)
最佳做法是不将后端模型公开到视图/前端。相反,应该构建仅包含视图需要呈现的数据并在视图和控制器之间传递数据的视图模型。
您还可以在视图模型中声明其他属性以适合您的需求。在您的情况下,我可以声明一个属性以包含每个部分的用户选择。
让我告诉你我的意思。
首先,我将魔术字符串“ Harvest”,“ Transfer”和“ Dispose”转换为枚举,因为我不喜欢使用魔术字符串:
namespace DL.SO.RadiosToController.WebUI.Models.Item
{
public enum PartActionType
{
Harvest,
Transfer,
Dispose
}
}
然后您可以制定所需的视图模型:
namespace DL.SO.RadiosToController.WebUI.Models.Item
{
public class ItemViewModel
{
[Required]
public int ItemId { get; set; }
public string ItemName { get; set; }
public string MFGNumber { get; set; }
public IList<ItemPartViewModel> Parts { get; set; }
}
public class ItemPartViewModel
{
[Required]
public int PartId { get; set; }
public string MFGNumber { get; set; }
public string PartName { get; set; }
// This is the additional property to contain what user picks
public PartActionType SelectedActionType { get; set; }
}
}
按照惯例,这些视图模型以及枚举应位于控制器模型视图中。假设您有一个ItemController
来显示项目,还有一些方法可以将用户选择保存在表单发布中,这些视图模型可以位于/ Models / Item /文件夹中。
我只是将它们的ID标记为必填项,因为我猜想您需要在表单发布中获取ID,以从持久性存储中检索数据。
然后从持久性存储中检索数据,构建视图模型并将其从控制器返回到视图:
namespace DL.SO.RadiosToController.WebUI.Controllers
{
public class ItemController : Controller
{
public ActionResult Index()
{
// Retrieve data from persistence storage and save it to the view model.
// But here I am just faking it.
var vm = new ItemViewModel
{
ItemId = 123,
ItemName = "Fake Item",
Parts = new List<ItemPartViewModel>
{
new ItemPartViewModel
{
PartId = 1,
PartName = "Part 1"
},
new ItemPartViewModel
{
PartId = 2,
PartName = "Part 2"
},
new ItemPartViewModel
{
PartId = 3,
PartName = "Part 3"
},
new ItemPartViewModel
{
PartId = 4,
PartName = "Part 4"
}
}
};
return View(vm);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Save(ItemViewModel model)
{
// Do what you need to do
return View();
}
}
}
最后,您可以构建视图:
<!--
Here I create an alias for the namespace so that I don't have to type
the long namespace every time.
-->
@using PartActionType = DL.SO.RadiosToController.WebUI.Models.Item.PartActionType
<!-- Here I declare the model for this view. -->
@model DL.SO.RadiosToController.WebUI.Models.Item.ItemViewModel
@{
ViewBag.Title = "Items";
<!-- I am getting the enum values and assign them to this local variable -->
var partActionTypes = Enum.GetValues(typeof(PartActionType));
}
@using (Html.BeginForm("save", "item", FormMethod.Post))
{
@Html.AntiForgeryToken()
@Html.HiddenFor(x => x.ItemId)
<table class="table table-sm text-center">
<thead>
<tr>
<th>Item ID</th>
<th>MFG ID</th>
<th>Item Name</th>
</tr>
</thead>
<tbody>
<tr>
<td>@Model.ItemId</td>
<td>@Model.MFGNumber</td>
<td>@Model.ItemName</td>
</tr>
</tbody>
</table>
<h5>Parts In Items (@Model.Parts.Count)</h5>
<table class="table table-sm text-center">
<thead>
<tr>
<th>Part ID</th>
<th>MFG ID</th>
<th>Part Name</th>
<!-- I'm displaying the names for the num dynamically. -->
@foreach (var actionType in partActionTypes)
{
<th>@Enum.GetName(typeof(PartActionType), actionType)</th>
}
</tr>
</thead>
<tbody>
@for (int i = 0; i < Model.Parts.Count; i++)
{
<tr>
<td>
@Html.DisplayFor(x => x.Parts[i].PartId)
@Html.HiddenFor(x => x.Parts[i].PartId)
</td>
<td>
@Html.DisplayFor(x => x.Parts[i].MFGNumber)
@Html.HiddenFor(x => x.Parts[i].MFGNumber)
</td>
<td>
@Html.DisplayFor(x => x.Parts[i].PartName)
@Html.HiddenFor(x => x.Parts[i].PartName)
</td>
@foreach (var actionType in partActionTypes)
{
<td>
@Html.RadioButtonFor(x => x.Parts[i].SelectedActionType, actionType)
</td>
}
</tr>
}
</tbody>
</table>
<button class="btn btn-success" type="submit">Save</button>
}
这里要注意的重要一件事是,构造零件行,而不是使用常规的@foreach()
,我必须使用带有索引的常规for循环。原因是当您使用@foreach()
时,这些输入的名称将是相同的,并且当您将输入回发到服务器时,服务器不会将它们视为列表。您将不得不使用带有索引的常规for循环,这样输入的名称将不同,因此服务器会将它们捕获为列表中的其他项:
<input id="Parts_2__SelectedActionType" name="Parts[2].SelectedActionType"
type="radio" value="Transfer">
您可能已经注意到了那些@Html.HiddenFor()
。默认情况下,该表单会将所有输入回发到服务器。如果要发布其他数据,可以使用@Html.HiddenFor()
,它将显示为隐藏的输入。
在表单发布中,您可以看到正确的单选按钮值已发布到服务器。
dotnet小提琴演示: https://dotnetfiddle.net/wbGsbd
Github中的示例代码: https://github.com/davidliang2008/DL.SO.RadiosToController