使用复选框回发带有标志的枚举 [英] Using checkboxes to PostBack Enum with Flags

查看:85
本文介绍了使用复选框回发带有标志的枚举的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个枚举属性,我试图通过复选框设置其值.枚举已标记,当用户选择多个选项时,我希望该属性将所有选定的标记串联在一起.

I have an enum property and I am trying to set its value through checkboxes. The enum is flagged and when the user selects multiple options I expect the property to have all the selected flags concatenated.

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

I tried adding a checkbox for each enum value and gave every checkbox the same name. During postback the first selected flag is retrieved but not concatenated with the other flags.

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

Could I fix this somehow without having separate property for each flag?

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

推荐答案

如果您检查POST正文,则发送的数据将无法正确接收.这是因为MVC不能很好地处理标志枚举.有人回答了类似的问题对此进行了描述:

If you check the POST body the data is sent, it is just not picked up properly. This is because MVC is not handling flags enumerations well. Someone who answered a similar question describes this:

通常,在设计视图模型时,我避免使用枚举,因为它们不能与ASP.NET MVC的帮助程序和现成的模型绑定程序一起使用.它们在您的域模型中非常好,但是对于视图模型,您可以使用其他类型.

In general I avoid using enums when designing my view models because they don't play with ASP.NET MVC's helpers and out of the box model binder. They are perfectly fine in your domain models but for view models you could use other types.

回答问题的人在那里也提供了如何绑定标记枚举的完整答案.您基本上需要做的是创建自己的自定义模型活页夹,该活页夹可以处理标志枚举.在另一篇名为 ASP.Net MVC标志枚举模型活页夹的文章中我找到一个例子,我将复制相关代码.

There the person answering the question also provides a full answer to how to bind a flags enumeration anyway. What you basically need to do is create your own custom model binder that can handle flags enumeration. In another post called ASP.Net MVC Flag Enumeration Model Binder I found an example and I will copy the relevant code.

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

Add a class called CustomModelBinder as follows:

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方法中注册自定义模型联编程序,如下所示:

Then in the Global.asax.cs Application_Start method register the custom model binder as follows:

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/

这篇关于使用复选框回发带有标志的枚举的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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