The approach you are using is correct. I agree with you in using always viewmodels and never ViewBag.
In your viewmodel you should change your dictionary to MultiSelectList so you can have the selected values also.
public IList<int> PriorInsuranceCompaniesSelected { get; set; }
public MultiSelectList PriorInsuranceCompanies { get; set; }
You then map the first field if some Ids are already selected (info that you get when loading data from your repo for example) and the second with all the values.
From your controller in the Get part (just some code as an example):
model.PriorInsuranceCompaniesSelected = new List<int>();
var companies = repository.GetPriorInsuranceCompanies();
//add to your PriorInsuranceCompaniesSelected the values already checked from your entity
var entity = repository.GetEntityBy(id);
if (entity.PriorInsuranceCompanies != null)
foreach (var item in entity.PriorInsuranceCompanies)
model.PriorInsuranceCompaniesSelected.Add(item.Id);
var select = (from s in companies select new { Id = s.Id, Name = s.Name }).OrderBy(x => x.Name); //.ToList;
model.PriorInsuranceCompanies = new MultiSelectList(select, "Id", "Name", model.PriorInsuranceCompaniesSelected);
Then in your Html you will have an output like this
@foreach (var item in Model.PriorInsuranceCompanies)
{
<label for="@item.Value" class="check">
<input type="checkbox" id="@item.Value" name="PriorInsuranceCompaniesSelected" value="@item.Value" @(item.Selected ? "checked" : "") />@item.Text</label>
}
On post, the ModelBinder will map the correct objects to your model automagically. You simply have to check values in model.PriorInsuranceCompaniesSelected
[HttpPost]
public ActionResult MyForm(MyViewModel model)
{
if (ModelState.IsValid)
{
try
{
//your mapping code or whatever...
//You do your things with the selected ids..
if (model.PriorInsuranceCompaniesSelected != null && model.PriorInsuranceCompaniesSelected.Count > 0)
entity.PriorInsuranceCompanies = repository.GetCompaniesBy(model.PriorInsuranceCompaniesSelected);
else
entity.PriorInsuranceCompanies = new List<Comapny>();
repository.Save(entity);
return RedirectToAction("Index");
}
catch (RulesException ex)
{
ex.CopyTo(ModelState);
}
catch
{
ModelState.AddModelError("", "My generic error taken form a resource");
}
}
//rehydratates the list in case of errors
//....
return View(model);
}
This should give you an idea of what to do. I hope it helps