绑定到CheckboxFor集合 [英] Binding to a collection of CheckboxFor

查看:198
本文介绍了绑定到CheckboxFor集合的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想实现一个许可屏幕中,用户可以得到一个特定的屏幕上的一个特定的权限。对于这个我生成Checkboxfor的集合,势必布尔属性的集合。但是,当我提交表单,我不是让所有的布尔属性真或假的全部,这取决于我是否初始化为真或假的视图模型构造这些属性。

I'm trying to implement a permission screen in which a user can be given a particular permission on a particular screen. For this I'm generating a collection of Checkboxfor, bound to a collection of bool properties. But when I submit the form, I'm either getting all bool properties true or all false, depending on whether I initialized these properties as true or false in the viewmodel constructor.

下面是code为视图模型:

Here is the code for the ViewModel:

方法一:

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

办法之二

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

下面是code我的观点:

Here is the code my the view:

方法一:

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

办法之二:

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

这里的code为控制器创建actionmethod:

Here's the code for the Create actionmethod in Controller:

    [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");
    }

当我检查视图模型的创建actionmethod,所有的IsAllowed属性是假的。如在视图模型构造器被初始化。没有办法检查/从视图中取消选中复选框的效果。

When I check the viewModel in the Create actionmethod, all the IsAllowed properties are false. As were initialized in the viewmodel contructor. There is no effect of checking/unchecking Checkboxes from the view.

我缺少的东西吗?

推荐答案

强类型HTML辅助,如CheckBoxFor用简单的前pressions作为第一个参数(财产和数组索引访问最多)才能正常工作。下面前pression东西完全脱离这个助手的能力:

Strongly typed HTML helpers such as the CheckBoxFor work only with simple expressions as first argument (property and array index access at most). The following expression is something completely out of the capacities of this helper:

m => m.Permissions.Where(s => s.SecurityId == security.Id && s.ScreenId == screen.Id).Single().IsAllowed

我会建议你使用一个真正的视图模型,并在控制器级别执行此您的域模型和视图模型之间的映射时。

I would recommend you to use a real view model and perform this at your controller level when mapping between your domain model and the view model.

更新:

显然,我对视图模型的答案是不够清晰,所以让我尝试举例说明我的意思的视图模式

Apparently my answer about view models wasn't clear enough, so let me try to exemplify what I mean by view models.

所以,我们首先来定义我们将需要实施所需的逻辑该视图视图模型:

So we start by defining our view models that will be required for implementing the required logic for this view:

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

然后,我们可以有一个控制器动作,将采取从一个仓库或东西,映射到视图模型获取的域模型的护理:

Then we could have a controller action that will take care of fetching the domain models from a repository or something and map to the view models:

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

和现在剩下的就是定义视图和相应的编辑/显示模板。

and now what's left is to define the view and the corresponding editor/display templates.

让我们先从主视图(〜/查看/主页/ 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 模型编辑模板(〜/查看/共享/ 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 模型编辑器模板(〜/查看/共享/ EditorTemplates / SecurityTypeViewModel.cshtml

@model SecurityTypeViewModel
<td>
    @Html.CheckBoxFor(x => x.IsAllowed)
    @Html.EditorFor(x => x.SecurityTypeId)
</td>

和最后的 SecurityTypeViewModel 模型显示模板(〜/查看/共享/ DisplayTemplates / SecurityTypeViewModel.cshtml ):

And finally the display template for the SecurityTypeViewModel model (~/Views/Shared/DisplayTemplates/SecurityTypeViewModel.cshtml):

@model SecurityTypeViewModel
<th>
    @Html.DisplayFor(x => x.SecurityName)
</th>

这就是pretty多少呢:

And that's pretty much it:

我已经离开你这里定义您的实际域模型和视图模型之间的映射关系。

I have left for you the mapping between your actual domain models and the view models defined here.

这篇关于绑定到CheckboxFor集合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆