使用带有标志的PostBack枚举复选框

时间:2015-07-14 19:11:08

标签: c# asp.net-mvc enums enum-flags

我有一个枚举属性,我试图通过复选框设置其值。枚举枚举,当用户选择多个选项时,我希望该属性连接所有选定的标记。

我尝试为每个枚举值添加一个复选框,并为每个复选框指定相同的名称。在回发期间,将检索第一个选定的标志,但不与其他标志连接。

我能否以某种方式解决这个问题而不为每个标志设置单独的属性?

模型

public class HomeModel
{
    public Fruit MyFruits { get; set; }
}

[Flags] public enum Fruit
{
    Love = 1,
    Joy = 2,
    Peace = 4,
    Patience = 8,
    Kindness = 16,
    Goodness = 32,
    Faithfulness = 64,
    Gentleness = 128,
    SelfControl = 256
}

视图

@model EnumFlagTest.Models.HomeModel
@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
</head>
<body>
    <div>
        @using (Html.BeginForm())
        {
            <h1>Fruits</h1>

            <div><label>@EnumFlagTest.Models.Fruit.Love.ToString() <input type="checkbox" name="MyFruits" value="@((int) EnumFlagTest.Models.Fruit.Love)" @(Model.MyFruits.HasFlag(EnumFlagTest.Models.Fruit.Love) ? "checked" : String.Empty) /></label></div>
            <div><label>@EnumFlagTest.Models.Fruit.Joy.ToString() <input type="checkbox" name="MyFruits" value="@((int) EnumFlagTest.Models.Fruit.Joy)" @(Model.MyFruits.HasFlag(EnumFlagTest.Models.Fruit.Joy) ? "checked" : String.Empty) /></label></div>
            <div><label>@EnumFlagTest.Models.Fruit.Peace.ToString() <input type="checkbox" name="MyFruits" value="@((int) EnumFlagTest.Models.Fruit.Peace)" @(Model.MyFruits.HasFlag(EnumFlagTest.Models.Fruit.Peace) ? "checked" : String.Empty) /></label></div>
            <div><label>@EnumFlagTest.Models.Fruit.Patience.ToString() <input type="checkbox" name="MyFruits" value="@((int) EnumFlagTest.Models.Fruit.Patience)" @(Model.MyFruits.HasFlag(EnumFlagTest.Models.Fruit.Patience) ? "checked" : String.Empty) /></label></div>
            <div><label>@EnumFlagTest.Models.Fruit.Kindness.ToString() <input type="checkbox" name="MyFruits" value="@((int) EnumFlagTest.Models.Fruit.Kindness)" @(Model.MyFruits.HasFlag(EnumFlagTest.Models.Fruit.Kindness) ? "checked" : String.Empty) /></label></div>
            <div><label>@EnumFlagTest.Models.Fruit.Goodness.ToString() <input type="checkbox" name="MyFruits" value="@((int) EnumFlagTest.Models.Fruit.Goodness)" @(Model.MyFruits.HasFlag(EnumFlagTest.Models.Fruit.Goodness) ? "checked" : String.Empty) /></label></div>
            <div><label>@EnumFlagTest.Models.Fruit.Faithfulness.ToString() <input type="checkbox" name="MyFruits" value="@((int) EnumFlagTest.Models.Fruit.Faithfulness)" @(Model.MyFruits.HasFlag(EnumFlagTest.Models.Fruit.Faithfulness) ? "checked" : String.Empty) /></label></div>
            <div><label>@EnumFlagTest.Models.Fruit.Gentleness.ToString() <input type="checkbox" name="MyFruits" value="@((int) EnumFlagTest.Models.Fruit.Gentleness)" @(Model.MyFruits.HasFlag(EnumFlagTest.Models.Fruit.Gentleness) ? "checked" : String.Empty) /></label></div>
            <div><label>@EnumFlagTest.Models.Fruit.SelfControl.ToString() <input type="checkbox" name="MyFruits" value="@((int) EnumFlagTest.Models.Fruit.SelfControl)" @(Model.MyFruits.HasFlag(EnumFlagTest.Models.Fruit.SelfControl) ? "checked" : String.Empty) /></label></div>

            <input type="submit" value="GO" />
        }
    </div>
</body>
</html>

控制器

[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Index()
{
    HomeModel model = new HomeModel();
    model.MyFruits = Fruit.Love | Fruit.Joy | Fruit.Peace | Fruit.Patience;
    return View(model);
}

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(HomeModel returnData)
{
    return View(returnData);
}

1 个答案:

答案 0 :(得分:6)

如果您检查POST正文,则会发送数据,但数据检测不正确。这是因为MVC没有很好地处理标志枚举。有人who answered提出类似问题:

  

一般情况下,我在设计视图模型时避免使用枚举,因为它们不能与ASP.NET MVC的帮助程序和开箱即用的模型绑定器一起使用。它们在您的域模型中非常精细,但对于视图模型,您可以使用其他类型。

回答问题的人还提供了如何绑定标志枚举的完整答案。你基本上需要做的是创建自己的自定义模型绑定器,它可以处理标志枚举。在另一篇名为ASP.Net MVC Flag Enumeration Model Binder的帖子中,我找到了一个示例,我将复制相关代码。

添加一个名为CustomModelBinder的类,如下所示:

public class CustomModelBinder : DefaultModelBinder
{
    protected override object GetPropertyValue(
        ControllerContext controllerContext, 
        ModelBindingContext bindingContext, 
        PropertyDescriptor propertyDescriptor, 
        IModelBinder propertyBinder)
    {
        var propertyType = propertyDescriptor.PropertyType;

        // Check if the property type is an enum with the flag attribute
        if (propertyType.IsEnum && propertyType.GetCustomAttributes(true).Any())
        {
            var providerValue = bindingContext.ValueProvider
                .GetValue(bindingContext.ModelName);
            if (providerValue != null)
            {
                var value = providerValue.RawValue;
                if (value != null)
                {
                    // In case it is a checkbox list/dropdownlist/radio 
                    // button list
                    if (value is string[])
                    {
                        // Create flag value from posted values
                        var flagValue = ((string[])value)
                            .Aggregate(0, (acc, i) 
                                => acc | (int)Enum.Parse(propertyType, i));

                        return Enum.ToObject(propertyType, flagValue);
                    }

                    // In case it is a single value
                    if (value.GetType().IsEnum)
                    {
                        return Enum.ToObject(propertyType, value);
                    }
                }
            }
        }

        return base.GetPropertyValue(controllerContext, 
            bindingContext, 
            propertyDescriptor, 
            propertyBinder);
    }
}

然后在Global.asax.cs Application_Start方法中注册自定义模型绑定器,如下所示:

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);

    // Register custom flag enum model binder
    ModelBinders.Binders.DefaultBinder = new CustomModelBinder();
}

这应该有用。

来源:http://itq.nl/asp-net-mvc-flag-enumeration-model-binder/