我们必须在Razor视图中将多个属性组合到一个EditorFor字段中。
我们有属性Quantity,UnitOfMeasure和Ingredient。这些需要组合,以便用户可以只输入他或她需要的东西,即10公斤土豆,而不是将信息输入多个领域。
完成此操作后,我们还需要对UOM和配料属性进行自动完成。
我为此代码创建了部分视图。
@model IEnumerable<RecipeApplication.Models.RecipeLine>
<div class="form-group">
@Html.Label("Ingrediënten", htmlAttributes: new { @class = "control-label col-md-2" })
<div>
@foreach (var item in Model)
{
<p>
@Html.EditorFor(modelItem => item.Quantity, new { htmlAttributes = new { @class = "form-control-inline" } })
@Html.EditorFor(modelItem => item.UnitOfMeasure.Abbreviation, new { htmlAttributes = new { @class = "form-control-inline" } })
@Html.EditorFor(modelItem => item.Ingredient.Name, new { htmlAttributes = new { @class = "form-control-inline" } })
</p>
}
</div>
</div>
显然这不是意图。
这是编辑功能的代码:
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
RecipeModel recipeModel = db.Recipes.Find(id);
if (recipeModel == null)
{
return HttpNotFound();
}
GetRecipeLines(id);
return View(recipeModel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "Name,Description,ImageUrl")] RecipeModel recipeModel, int?id)
{
if (ModelState.IsValid)
{
db.Entry(recipeModel).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
GetRecipeLines(id);
return View(recipeModel);
}
我查看了Google和StackOverflow,但我找不到合适的答案来完成这项工作。
就我个人而言,我现在甚至不知道从哪里开始。
我希望有人可以帮助解决这个问题。
感谢。
答案 0 :(得分:3)
在ReceipLine上添加新的getter属性
C#6.0语法:
public string QuantityUomIngredient =>
$"{Quantity} {UnitOfMeasure?.Abbreviation ?? ""} {Ingredient?.Name ?? ""}";
然后你的观点应该是这样的
@Html.EditorFor(modelItem => item.QuantityUomIngredient ...
然后构建一个自定义模型绑定器,将QuantityUomIngredient解析为其相应的属性(这部分实现起来应该很有趣)。但是一定要对输入进行一次很好的验证,这样你就可以解析好的数据了。
答案 1 :(得分:0)
感谢anwer Leo Nix,它肯定会让我走向正确的方向。
这是我到目前为止编写的代码,它看起来像一个魅力。 (我还没有包含错误处理。)
public class RecipeLine
{
[Key]
public int RecipeLineId { get; set; }
public int RecipeId { get; set; }
public double Quantity { get; set; }
public virtual UnitOfMeasureModel UnitOfMeasure { get; set; }
public virtual IngredientModel Ingredient { get; set; }
public string QuantityUomIngredient => $"{Quantity} {UnitOfMeasure?.Abbreviation ?? ""} {Ingredient?.Name ?? ""}";
}
我写的自定义Binder。这个做了一些额外的研究。
class RecipeLineCustomBinder : DefaultModelBinder
{
private RecipeApplicationDb db = new RecipeApplicationDb();
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
HttpRequestBase request = controllerContext.HttpContext.Request;
// Get the QuantityCustomIngredient from the webform.
string quantityUomIngredient = request.Form.Get("QuantityUomIngredient");
// Get the IngredientID from the webform.
int recipeID = int.Parse(request.Form.Get("RecipeId"));
// Split the QuantityCustomIngredient into seperate strings.
string[] quantityUomIngredientArray = quantityUomIngredient.Split();
//string[] quantityUomIngredientArray = quantityUomIngredient.Split(new string[] { " " }, 2, StringSplitOptions.RemoveEmptyEntries);
if (quantityUomIngredientArray.Length >= 3)
{
// Get the quantity value
double quantityValue;
bool quantity = double.TryParse(quantityUomIngredientArray[0], out quantityValue);
// Get the UOM value.
string uom = quantityUomIngredientArray[1];
UnitOfMeasureModel unitOfMeasure = null;
bool checkUOM = (from x in db.UnitOfMeasures
where x.Abbreviation == uom
select x).Count() > 0;
if (checkUOM)
{
unitOfMeasure = (from x in db.UnitOfMeasures
where x.Abbreviation == uom
select x).FirstOrDefault();
}
// Get the ingredient out of the array.
string ingredient = "";
for (int i = 2; i < quantityUomIngredientArray.Length; i++)
{
ingredient += quantityUomIngredientArray[i];
if (i != quantityUomIngredientArray.Length - 1)
{
ingredient += " ";
}
}
bool checkIngredient = (from x in db.Ingredients where x.Name == ingredient select x).Count() > 0;
IngredientModel Ingredient = null;
if (checkIngredient)
{
Ingredient = (from x in db.Ingredients
where x.Name == ingredient
select x).FirstOrDefault();
}
// Return the values.
return new RecipeLine
{
Quantity = quantityValue,
UnitOfMeasure = unitOfMeasure,
Ingredient = Ingredient,
RecipeId = recipeID
};
}
else
{
return null;
}
}
}
在Razor视图中,这是我使用的代码:
<div class="form-group">
@Html.LabelFor(model => model.QuantityUomIngredient, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.QuantityUomIngredient, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.QuantityUomIngredient, "", new { @class = "text-danger" })
</div>
</div>
我在Global.asax.cs中添加了自定义绑定器
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
ModelBinders.Binders.Add(typeof(RecipeLine), new RecipeLineCustomBinder());
}
}
最后将自定义活页夹添加到控制器
[HttpPost]
public ActionResult Create([ModelBinder(typeof(RecipeLineCustomBinder))] RecipeLine recipeLine)
{
if (ModelState.IsValid)
{
db.RecipeLines.Add(recipeLine);
db.SaveChanges();
return RedirectToAction("Index", new { id = recipeLine.RecipeId });
}
return View(recipeLine);
}
我希望这对其他开发者也有帮助。