使用ASP.NET Core Razor页面,是否可以将选择列表绑定到复杂对象而无需在PageModel中具有ID属性?
我有这些模型类:
public class Department
{
[HiddenInput]
public int ID { get; set; }
[Display(Name = "Name")]
[Required(ErrorMessage = "{0} must be specified.")]
[StringLength(50, MinimumLength = 1, ErrorMessage = "{0} has to be {2} to {1} characters long.")]
public string Name { get; set; }
}
public class User
{
[HiddenInput]
public int ID { get; set; }
[Display(Name = "Name")]
[Required(ErrorMessage = "{0} must be specified.")]
[StringLength(50, MinimumLength = 1, ErrorMessage = "{0} has to be {2} to {1} characters long.")]
public string Name { get; set; }
[Display(Name = "Department")]
[Required(ErrorMessage = "{0} must be specified.")]
public Department Department { get; set; }
}
我已经创建了一个用于编辑用户的视图,包括选择部门。这是我的PageModel:
public class EditModel : PageModel
{
private readonly IUserRepository _userRepository;
[BindProperty(BinderType = typeof(UserModelBinder))]
public User UserToEdit { get; set; }
public SelectList DepartmentsSL { get; set; }
public EditModel(IUserRepository userRepository)
{
_userRepository = userRepository;
}
public void OnGet(int id)
{
UserToEdit = _userRepository.GetUser(id);
PopulateSelectList();
}
public IActionResult OnPost()
{
if (!ModelState.IsValid)
{
PopulateSelectList();
return Page();
}
var success = _userRepository.UpdateUser(UserToEdit);
if (success)
{
return RedirectToPage("./Index");
}
else
{
throw new Exception("Could not save the user.");
}
}
private void PopulateSelectList()
{
var departments = _userRepository.GetAllDepartments();
DepartmentsSL = new SelectList(departments, nameof(Department.ID), nameof(Department.Name), UserToEdit.Department.ID);
}
}
...这是我的观点:
@page
@model ProjectName.Pages.Admin.Users.EditModel
@{
ViewData["Title"] = "Edit user";
}
<h1>Edit user</h1>
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input asp-for="UserToEdit.ID" />
<div class="form-group">
<label asp-for="UserToEdit.Name" class="control-label"></label>
<input asp-for="UserToEdit.Name" class="form-control" />
<span asp-validation-for="UserToEdit.Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="UserToEdit.Department" class="control-label"></label>
<select asp-for="UserToEdit.Department" class="form-control" asp-items="@Model.DepartmentsSL">
<option value="">Choose department</option>
</select>
<span asp-validation-for="UserToEdit.Department" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-primary" />
<a asp-page="./Index" class="btn btn-secondary">Cancel</a>
</div>
</form>
您可能已经在PageModel中注意到了,我正在使用自定义modelbinder。我写这个是为了在视图发回时正确设置用户的部门。
public class UserModelBinder : IModelBinder
{
private readonly IUserRepository _userRepository;
public UserModelBinder(IUserRepository userRepository)
{
_userRepository = userRepository;
}
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
{
throw new ArgumentNullException("bindingContext");
}
var modelName = bindingContext.ModelName;
var user = new User();
// ID.
var idValue = bindingContext.ValueProvider.GetValue(modelName + ".ID");
if (idValue != ValueProviderResult.None)
{
bindingContext.ModelState.SetModelValue(modelName + ".ID", idValue);
var idString = idValue.FirstValue;
if (!String.IsNullOrEmpty(idString))
{
var id = Convert.ToInt32(idString);
user.ID = id;
}
}
// Department.
var departmentValue = bindingContext.ValueProvider.GetValue(modelName + ".Department");
if (departmentValue != ValueProviderResult.None)
{
bindingContext.ModelState.SetModelValue(modelName + ".Department", departmentValue);
var departmentIdString = departmentValue.FirstValue;
if (!String.IsNullOrEmpty(departmentIdString))
{
var departmentId = Convert.ToInt32(departmentIdString);
user.Department = _userRepository.GetDepartment(departmentId);
}
}
bindingContext.Result = ModelBindingResult.Success(user);
return Task.CompletedTask;
}
}
现在,所有这些似乎都可以正常工作-我可以更改名称和部门,并且可以正确地发回。验证也可以。但是,当打开此编辑视图时,未在选择列表中选择用户的当前部门。
在EditModel.PopulateSelectList()中,我尝试了不同的方法,但是似乎都没有用。
DepartmentsSL = new SelectList(departments, nameof(Department.ID), nameof(Department.Name), UserToEdit.Department);
DepartmentsSL = new SelectList(departments, nameof(Department.ID), nameof(Department.Name), UserToEdit.Department.ID);
DepartmentsSL = new SelectList(departments, nameof(Department.ID), nameof(Department.Name), UserToEdit.Department.Name);
是否可以解决最后一部分?
到目前为止,我所看到的解决方案是在PageModel中具有一个单独的属性“ DepartmentID”并绑定到该属性,然后在回发后设置User的Department属性。我想那也意味着我可以摆脱自定义模型联编程序,但是我真的很想看看我当前的解决方案是否可以一路采用。 :)
打开此编辑视图时,未在选择列表中选择用户的当前部门
您可以尝试从SelectTagHelper中删除asp-for="UserToEdit.Department"
并手动设置name="UserToEdit.Department"
,如下所示。
<select name="UserToEdit.Department" class="form-control" asp-items="@Model.DepartmentsSL">
<option value="">Choose department</option>
</select>
并为SelectList设置selectedValue,如下所示。
DepartmentsSL = new SelectList(departments, nameof(Department.ID), nameof(Department.Name), UserToEdit.Department.ID);
测试结果
此外,另一种可能的方法是创建custom tag helper来渲染元素并根据您的实际模型数据和要求设置选定的值。