C# 发布到模型的MVC DropDownList值未绑定
DropDownLists可能是我最不喜欢使用MVC框架的部分。我的表单中有几个下拉列表,我需要将它们的选定值传递给接受模型作为其参数的ActionResult 标记如下所示:C# 发布到模型的MVC DropDownList值未绑定,c#,asp.net-mvc-3,drop-down-menu,model-binding,C#,Asp.net Mvc 3,Drop Down Menu,Model Binding,DropDownLists可能是我最不喜欢使用MVC框架的部分。我的表单中有几个下拉列表,我需要将它们的选定值传递给接受模型作为其参数的ActionResult 标记如下所示: <div class="editor-label"> @Html.LabelFor(model => model.FileType) </div> <div class="editor-field"> @Html.DropDownListFor(model =&g
<div class="editor-label">
@Html.LabelFor(model => model.FileType)
</div>
<div class="editor-field">
@Html.DropDownListFor(model => model.FileType.Variety, (SelectList)ViewBag.FileTypes)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Status)
</div>
<div class="editor-field">
@Html.DropDownListFor(model => model.Status.Status, (SelectList)ViewBag.Status)
</div>
[HttpPost]
public ActionResult Create(int reviewid, ReviewedFile file)
{
if (ModelState.IsValid)
{
UpdateModel(file);
}
//repository.Add(file);
return RedirectToAction("Files", "Reviews", new { reviewid = reviewid, id = file.ReviewedFileId });
}
这应该很好,除了下拉列表中的值被发布为null。当我进一步研究ModelState错误时,发现原因是:
类型的参数转换
要键入的“System.String”
'PeerCodeReview.Models.outcome状态'
失败,因为无法使用类型转换器
在这些类型之间转换
不应该这么难,但确实如此。所以问题是,;为了正确绑定模型属性,我需要做什么
顺便说一句,我知道我可以传入FormCollection对象,但这意味着更改单元测试中当前需要强类型模型参数的重要部分。您需要为绑定到下拉列表的两个属性创建并注册自定义模型绑定器 以下是我为一个模型活页夹编写的代码,我正是为此目的而构建的:
public class LookupModelBinder<TModel> : DefaultModelBinder
where TModel : class
{
private string _key;
public LookupModelBinder(string key = null)
{
_key = key ?? typeof(TModel).Name;
}
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var dbSession = ((IControllerWithSession)controllerContext.Controller).DbSession;
var modelName = bindingContext.ModelName;
TModel model = null;
ValueProviderResult vpResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (vpResult != null)
{
bindingContext.ModelState.SetModelValue(modelName, vpResult);
var id = (int?)vpResult.ConvertTo(typeof(int));
model = id == null ? null : dbSession.Get<TModel>(id.Value);
}
if (model == null)
{
ModelValidator requiredValidator = ModelValidatorProviders.Providers.GetValidators(bindingContext.ModelMetadata, controllerContext).Where(v => v.IsRequired).FirstOrDefault();
if (requiredValidator != null)
{
foreach (ModelValidationResult validationResult in requiredValidator.Validate(bindingContext.Model))
{
bindingContext.ModelState.AddModelError(modelName, validationResult.Message);
}
}
}
return model;
}
}
这假定下拉列表控件的名称与类型名称相同。如果没有,则可以将密钥传递给模型绑定器
binders[typeof(EmploymentType)] = new LookupModelBinder<EmploymentType>("ControlName");
您需要为绑定到下拉列表的两个特性创建并注册自定义模型绑定器 以下是我为一个模型活页夹编写的代码,我正是为此目的而构建的:
public class LookupModelBinder<TModel> : DefaultModelBinder
where TModel : class
{
private string _key;
public LookupModelBinder(string key = null)
{
_key = key ?? typeof(TModel).Name;
}
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var dbSession = ((IControllerWithSession)controllerContext.Controller).DbSession;
var modelName = bindingContext.ModelName;
TModel model = null;
ValueProviderResult vpResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (vpResult != null)
{
bindingContext.ModelState.SetModelValue(modelName, vpResult);
var id = (int?)vpResult.ConvertTo(typeof(int));
model = id == null ? null : dbSession.Get<TModel>(id.Value);
}
if (model == null)
{
ModelValidator requiredValidator = ModelValidatorProviders.Providers.GetValidators(bindingContext.ModelMetadata, controllerContext).Where(v => v.IsRequired).FirstOrDefault();
if (requiredValidator != null)
{
foreach (ModelValidationResult validationResult in requiredValidator.Validate(bindingContext.Model))
{
bindingContext.ModelState.AddModelError(modelName, validationResult.Message);
}
}
}
return model;
}
}
这假定下拉列表控件的名称与类型名称相同。如果没有,则可以将密钥传递给模型绑定器
binders[typeof(EmploymentType)] = new LookupModelBinder<EmploymentType>("ControlName");
请尝试以下方法:
<div class="editor-label">
@Html.LabelFor(model => model.FileType)
</div>
<div class="editor-field">
@Html.DropDownListFor(model => model.FileType.Id, (SelectList)ViewBag.FileTypes)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Status)
</div>
<div class="editor-field">
@Html.DropDownListFor(model => model.Status.Id, (SelectList)ViewBag.Status)
</div>
请尝试以下方法:
<div class="editor-label">
@Html.LabelFor(model => model.FileType)
</div>
<div class="editor-field">
@Html.DropDownListFor(model => model.FileType.Id, (SelectList)ViewBag.FileTypes)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Status)
</div>
<div class="editor-field">
@Html.DropDownListFor(model => model.Status.Id, (SelectList)ViewBag.Status)
</div>
另外,这里不需要UpdateModelfile,因为发布的表单值已经包含在ReviewFileFile参数中。我只需要它来检查ModelState错误。一旦我找到解决问题的方法,它就会运行。另外,您不需要在其中包含UpdateModelfile,因为发布的表单值已经包含在您的ReviewedFile参数中。我只需要它来检查ModelState错误。一旦我找到解决问题的方法,它就开始运行了。这是一个很好的建议,但我已经尝试过了,同样的错误仍然存在——MVC不知道如何将字符串值转换为相应的对象属性,例如ReviewedFile.FileTypeI无法重新设置。我已经设置了一个快速项目并模拟了您的类,但MVC为我将字符串值转换为对象属性。例如,如果我进入Create操作并检查file.FileType的值,就会得到一个FileType类型的对象,其值为{Id=2,variation=null}。它可能不是完整的对象,但有足够的信息从repo检索它。它到底为您做了什么?很好的建议,但我已经尝试过了,同样的错误仍然存在-MVC不知道如何将字符串值转换为相应的对象属性,例如ReviewDefile.FileTypeI无法重新编程。我已经设置了一个快速项目并模拟了您的类,但MVC为我将字符串值转换为对象属性。例如,如果我进入Create操作并检查file.FileType的值,就会得到一个FileType类型的对象,其值为{Id=2,variation=null}。它可能不是完整的对象,但有足够的信息从repo检索它。它到底为你做了什么?