这是我的问题。我有一个显示给用户的模型列表。左侧是每个型号的复选框,表示用户想要选择此型号(在这种情况下,我们正在构建用户可以添加到购物车中的产品)。该模型没有被选择的概念......它严格地包含有关产品的信息。
我已经和其他一些开发人员谈过了,我能想到的最好的是获得formcollection和字符串解析键值来确定是否选中了复选框。这似乎并不理想。我当时认为会有更强烈的约束,但我无法找到办法。
我尝试创建另一个模型,该模型具有一个布尔属性来表示被检查和模型的属性,并将该模型类型的列表传递给视图,并在控制器上创建一个ActionResult,接受新模型的列表/检查属性,但它返回null。我只是想像Web表单一样,应该继续解析复选框值吗?
以下是我在集合中包装模型所做的工作:
public class SelectableCollection[T] : IList[T] {}
public class SelectableTrack{
public bool IsChecked{get;set;}
public bool CurrentTrack{get;set;}
}
对于视图,我继承自
ViewPage[SelectableCollection[SelectableTrack]]
对于控制器,我将其作为ActionResult:
[HttpPost]
public ActionResult SelectTracks(SelectableCollection sc) {
return new EmptyResult();
}
但是当我在ActionResult内部进行分解时,该集合为null。有什么原因导致它没有通过?
答案 0 :(得分:1)
这是ViewModel有用的情况。您需要能够表示“选定”项目,这些项目不属于您的模型,但您可以将其添加到ViewModel。 ViewModels旨在为视图提供所有所需的信息,包括一些可能不属于模型的信息。
这是一个想法:是否可以将您的项目“包装”在一个表示选择的集合中?我正在考虑SelectableCollection<T>
之类的东西(这可能来自ICollection<T>
或其他一些通用集合类型。)您可以将其添加到ViewModel并将复选框绑定到它们。
答案 1 :(得分:1)
在你的情况下,我会添加一个ViewModel,它扩展你的模型,其概念是“被选中”。这将允许您使用MVC的模型绑定技术来避免在表单集合中进行挖掘。
在我发现AutoMapper之前,我非常不愿意加入ViewModel。现在我已经拥有了AutoMapper,我可以根据自己的应用需求制作尽可能多的ViewModel,并且可以轻松地将我的ViewModel映射回我的(DTO)模型以实现持久性。
另外,WRT ASP.NET MVC复选框,你应该熟悉如何处理Checkboxs的一些怪癖。有关其他详细信息,请参阅this question。
我个人使用此方法从我的模型绑定器中的bindingContext获取bool值,其中正在使用复选框:
public static bool? GetBool(ModelBindingContext bindingContext, string key)
{
var str = GetStr(bindingContext, key);
bool tmp;
if (string.IsNullOrEmpty(str))
return null;
str = str.ToLower().Trim();
if (bool.TryParse(str, out tmp))
return tmp;
if (string.Compare(str, "no") == 0)
return false;
if (string.Compare(str, "yes") == 0)
return true;
if (string.Compare(str, "true,false") == 0)
return true;
return null;
}
public static string GetStr(ModelBindingContext bindingContext, string key)
{
if (string.IsNullOrEmpty(key))
return null;
var valueResult = bindingContext
.ValueProvider
.GetValue(bindingContext.ModelName + "." + key);
if (valueResult == null && bindingContext.FallbackToEmptyPrefix)
valueResult = bindingContext.ValueProvider.GetValue(key);
return valueResult != null ? valueResult.AttemptedValue : null;
}
答案 2 :(得分:0)
由于<%= Html.CheckBox() %>
为每个复选框呈现<input name="yourName" type="hidden" value="false" />
以跟踪未选中的复选框,因此我使用以下解决方案:
控制器
public ActionResult MyAction([Bind(Prefix = "CheckBox")] Dictionary<int, bool> myCheckBoxes)
{
}
视图模型
public List<CheckBox> MyCheckBoxes{ get; private set; }
MyCheckBoxes = modelRepository.GetMyCheckBoxes(userID);
存储库
public List<CheckBox> GetMyCheckBoxes(userID)
{
IDictionary<int, bool> selectedModels = new Dictionary<int, bool>();
ModelRespository modelRespository = new ModelRespository();
foreach (var model in modelRespository.GetUserSelectedModels(userID))
{
selectedModels.Add(model.ModelID);
}
return (from m in modelRespository.GetModels()
select new CheckBox
{
ID = m.ModelID.ToString(),
Text = m.Name,
Checked = selectedModels.ContainsKey(m.ID)
}).ToList();
}
查看
<% int i = 0; foreach (CheckBox c in Model.MyCheckBoxes)
{ %>
<p>
<%= Html.Hidden(String.Format("CheckBox[{0}].Key", i), yourModelID)%>
<%= Html.CheckBox(String.Format("CheckBox[{0}].Value", i), c.Checked)%>
</p>
<% i++; } %>