开发者

How to find the Checked Status of All Checkboxes

Here is my problem. I have a list of models that are displayed to the user. On the left is a checkbox for each model to indicate that the user wants to choose this model (in this case, we're building products a user can add to their shopping cart). The model has no concept of being chosen...it strictly has information about the product in question.

I've talked with a few other developers after having gone through and the best I could come up with is getting the formcol开发者_高级运维lection and string parsing the key values to determine whether the checkbox is checked or not. This doesn't seem ideal. I was thinking there would be something more strongly bound, but I can't figure out a way to do it.

I tried creating another model that had a boolean property to represent being checked and a property of the model and passing a list of that model type to the view and creating a ActionResult on the controller that accepts a list of the new model / checked property, but it comes back null. Am I just thinking too much like web forms and should just continue on with parsing checkbox values?

Here's what I've done for wrapping the models inside a collection:


public class SelectableCollection[T] : IList[T] {}
public class SelectableTrack{
  public bool IsChecked{get;set;}
  public bool CurrentTrack{get;set;}
}

For the view, I inherit from


ViewPage[SelectableCollection[SelectableTrack]]

For the controller, I have this as the ActionResult:


[HttpPost]
        public ActionResult SelectTracks(SelectableCollection sc) {

            return new EmptyResult();
        }

But when I break inside the ActionResult, the collection is null. Any reason why it isn't coming through?


This is a case where ViewModels are useful. You need to be able to represent "selected" items, which isn't a part of your Model, but you can add it to a ViewModel. ViewModels are designed to provide all the information you need for a View, including some that may not be part of the Model.

Here's an idea: would it be possible to "wrap" your items in a collection that indicates selection? I'm thinking of something like SelectableCollection<T> (this could derive from ICollection<T> or some other generic collection type.) You could add this to your ViewModels and bind your checkboxes to them.


In your case, I would add a ViewModel that extends your Model with the concept of being "selected". This would allow you to use MVC's model binding techniques to avoid digging around in form collections.

I was pretty reluctant to get on the ViewModel bandwagon until I found out about AutoMapper. Now that I have AutoMapper, I feel free to make as many ViewModels as my app needs, and can easily map my ViewModel back to my (DTO) Model for persistence.

Also, WRT ASP.NET MVC Checkboxes, you would do well to familiarize yourself with some quirks in how Checkboxes are handled. See this question for additional details.

I personally use this method to get a bool value from the bindingContext in my model binders where checkboxes are in use:

    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;
    }


Because <%= Html.CheckBox() %> renders a <input name="yourName" type="hidden" value="false" /> for every checkbox to keep track of unchecked boxes, I use the following solution:

Controller

public ActionResult MyAction([Bind(Prefix = "CheckBox")] Dictionary<int, bool> myCheckBoxes)
{
}

ViewModel

public List<CheckBox> MyCheckBoxes{ get; private set; }

MyCheckBoxes = modelRepository.GetMyCheckBoxes(userID);

Repository

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();
}

View

<% 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++; } %>
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜