我正在尝试实现一个权限屏幕,在该权限屏幕中,用户可以在特定屏幕上获得特定权限。为此,我将生成一个Checkboxfor集合,绑定到bool属性的集合。但是当我提交表单时,我要么将所有bool属性设置为true,要么全部为false,这取决于我是否在viewmodel构造函数中将这些属性初始化为true或false。
以下是ViewModel的代码:
方法I:
public class MyViewModel
{
public MyModel Model { get; set; }
public IEnumerable<ScreenType> Screens { get; set; }
public IEnumerable<SecurityType> SecurityTypes { get; set; }
public List<PermissionType> Permissions { get; set; }
public MyViewModel()
{
LoadScreens();
LoadSecurityTypes();
LoadPermissions();
}
public void LoadPermissions()
{
Permissions = new List<PermissionType>();
foreach (var screen in Screens)
{
foreach (var securityType in SecurityTypes)
{
Permissions.Add(
new PermissionType
{
PermissionId= Guid.NewGuid(),
ScreenId= screen.Id,
SecurityId = securityType.Id,
IsAllowed = false
});
}
}
}
}
方法II
public class MyViewModel
{
public MyModel Model { get; set; }
public IEnumerable<ScreenType> Screens { get; set; }
public IEnumerable<SecurityType> SecurityTypes { get; set; }
public List<bool> AllowedList { get; set; }
public MyViewModel()
{
LoadScreens();
LoadSecurityTypes();
LoadPermissions();
}
public void LoadPermissions()
{
AllowedList = new List<bool>();
foreach (var form in Forms)
{
foreach (var security in Securities)
{
AllowedList.Add(false);
}
}
}
}
以下是我的观点代码:
方法I:
@using (Ajax.BeginForm("Create", "Role", null, new AjaxOptions { UpdateTargetId = "addStatus", InsertionMode = InsertionMode.Replace, OnSuccess = "onFormPostSuccess" }, new { @id = "AddForm" }))
{
<div>
<span><label>Screen</label></span>
@foreach (var security in Model.SecurityTypes)
{
<span><label>@security.Name</label></span>
}
<br />
@foreach (var screen in Model.Screens)
{
<span>@screen.Name</span>
foreach (var security in Model.SecurityTypes)
{
<span>@Html.CheckBoxFor(m => m.Permissions.Where(s => s.SecurityId == security.Id && s.ScreenId == screen.Id).Single().IsAllowed, new { @id = HtmlHelper.GenerateIdFromName("Create" + screen.Name + security.Name) })</span>
}
<br />
}
</div>
<div>
<span>
<input type="image" src="/content/images/submit_button.png" value="submit" />
</span>
</div>
<div>
<span id="addStatus" class="submitStatus"></span>
</div>
}
方法II:
@using (Ajax.BeginForm("Create", "Role", null, new AjaxOptions { UpdateTargetId = "addStatus", InsertionMode = InsertionMode.Replace, OnSuccess = "onFormPostSuccess" }, new { @id = "AddForm" }))
{
<div>
<span><label>Screen</label></span>
@foreach (var security in Model.SecurityTypes)
{
<span><label>@security.Name</label></span>
}
<br />
@foreach (int i=0; i < Model.Screens.Count(); i++)
{
<span>@Model.Screens.ElementAt(i).Name</span>
foreach (int j=0; j<Model.SecurityTypes.Count(); j++)
{
@* The index 5*i+j is because I have 5 security types *@
<span>@Html.CheckBoxFor(Model.AllowedList[5*i+j], new { @id = HtmlHelper.GenerateIdFromName("Create" + @Model.Screens.ElementAt(i).Name + @Model.SecurityTypes.ElementAt(j).Name) })</span>
}
<br />
}
</div>
<div>
<span>
<input type="image" src="/content/images/submit_button.png" value="submit" />
</span>
</div>
<div>
<span id="addStatus" class="submitStatus"></span>
</div>
}
以下是Controller中Create actionmethod的代码:
[Authorize]
[HttpPost]
public JsonResult Create(MyViewModel viewModel)
{
if ( ModelState.IsValid)
{
if (service.AddRole(viewModel))
{
return Json("Role Added !");
}
return Json("Role exists !");
}
return Json("Please correct errors");
}
当我在Create actionmethod中检查viewModel时,所有IsAllowed属性都为false。在viewmodel构造函数中初始化。从视图中选中/取消选中复选框没有任何效果。
我错过了什么吗?
答案 0 :(得分:8)
强类型的HTML帮助程序(如CheckBoxFor)仅使用简单表达式作为第一个参数(最多属性和数组索引访问)。以下表达式完全取决于此帮助程序的功能:
m => m.Permissions.Where(s => s.SecurityId == security.Id && s.ScreenId == screen.Id).Single().IsAllowed
我建议您使用实际视图模型,并在域模型和视图模型之间进行映射时在控制器级别执行此操作。
更新:
显然我对视图模型的回答不够明确,所以让我试着用视图模型来举例说明我的意思。
因此,我们首先定义实现此视图所需逻辑所需的视图模型:
public class CreateViewModel
{
public IEnumerable<ScreenViewModel> Screens { get; set; }
}
public class ShowCreateViewModel: CreateViewModel
{
public IEnumerable<SecurityTypeViewModel> SecurityTypes { get; set; }
}
public class ScreenViewModel
{
public string ScreenName { get; set; }
[HiddenInput(DisplayValue = false)]
public int ScreenId { get; set; }
public IEnumerable<SecurityTypeViewModel> SecurityTypes { get; set; }
}
public class SecurityTypeViewModel
{
public string SecurityName { get; set; }
[HiddenInput(DisplayValue = false)]
public int SecurityTypeId { get; set; }
public bool IsAllowed { get; set; }
}
然后我们可以有一个控制器动作,它将负责从存储库或其他东西中获取域模型并映射到视图模型:
public class HomeController : Controller
{
public ActionResult Create()
{
// The information will obviously come from a domain model that
// we map to a view model, but for the simplicity of the answer
// I am hardcoding the values here
var securityTypes = new[]
{
new SecurityTypeViewModel { SecurityTypeId = 1, SecurityName = "security 1" },
new SecurityTypeViewModel { SecurityTypeId = 2, SecurityName = "security 2" },
new SecurityTypeViewModel { SecurityTypeId = 3, SecurityName = "security 3" },
};
// The information will obviously come from a domain model that
// we map to a view model, but for the simplicity of the answer
// I am hardcoding the values here
return View(new ShowCreateViewModel
{
SecurityTypes = securityTypes,
Screens = new[]
{
new ScreenViewModel
{
ScreenId = 1,
ScreenName = "Screen 1",
SecurityTypes = securityTypes
},
new ScreenViewModel
{
ScreenId = 2,
ScreenName = "Screen 2",
SecurityTypes = securityTypes
},
}
});
}
[HttpPost]
public ActionResult Create(CreateViewModel model)
{
// The view model passed here will contain all the necessary information
// for us to be able to perform the actual Save:
// a list of the screen ids along with a list of the selected permission ids
return Content(
"Thank you for selecting the following allowed permissions:<br/>" +
string.Join("<br/>", model.Screens.Select(s => string.Format(
"screen id: {0}, permission ids: {1}",
s.ScreenId,
string.Join(",", s.SecurityTypes.Where(st => st.IsAllowed).Select(st => st.SecurityTypeId))
)))
);
}
}
现在剩下的就是定义视图和相应的编辑器/显示模板。
让我们从主视图(~/Views/Home/Create.cshtml
)开始:
@model ShowCreateViewModel
<script src="@Url.Content("~/Scripts/jquery.unobtrusive-ajax.js")" type="text/javascript"></script>
@using (Ajax.BeginForm("Create", "Home", null, new AjaxOptions { UpdateTargetId = "addStatus", InsertionMode = InsertionMode.Replace, OnSuccess = "onFormPostSuccess" }, new { @id = "AddForm" }))
{
<table>
<thead>
<tr>
<th>Screen/Security type</th>
@Html.DisplayFor(x => x.SecurityTypes)
</tr>
</thead>
<tbody>
@Html.EditorFor(x => x.Screens)
</tbody>
</table>
<div>
<input type="submit" value="submit" />
</div>
<div id="addStatus" class="submitStatus"></div>
}
接下来,我们有ScreenViewModel
模型(~/Views/Shared/EditorTemplates/ScreenViewModel.cshtml
)的编辑器模板:
@model ScreenViewModel
<tr>
<td>
@Html.DisplayFor(x => x.ScreenName)
@Html.EditorFor(x => x.ScreenId)
</td>
@Html.EditorFor(x => x.SecurityTypes)
</tr>
然后是SecurityTypeViewModel
模型(~/Views/Shared/EditorTemplates/SecurityTypeViewModel.cshtml
)的编辑器模板:
@model SecurityTypeViewModel
<td>
@Html.CheckBoxFor(x => x.IsAllowed)
@Html.EditorFor(x => x.SecurityTypeId)
</td>
最后是SecurityTypeViewModel
模型(~/Views/Shared/DisplayTemplates/SecurityTypeViewModel.cshtml
)的显示模板:
@model SecurityTypeViewModel
<th>
@Html.DisplayFor(x => x.SecurityName)
</th>
这就是它:
我已经为您提供了实际域模型与此处定义的视图模型之间的映射。