Html.EnumDropdownListFor: 显示默认文本

71

在我看来,我有一个枚举下拉列表(这是Asp.Net MVC 5.1的新功能)。

@Html.EnumDropDownListFor(m => m.SelectedLicense,new { @class="form-control"})

如果我执行上面的代码,我会得到下拉列表,以显示以下枚举的内容。

public enum LicenseTypes
{
    Trial = 0,
    Paid = 1
}

但默认情况下,我希望我的下拉列表有一个值(自定义文本),这是我尝试过的方法:

@Html.EnumDropDownListFor(m => m.SelectedLicense,"Select a license" ,new { @class="form-control"})

但现在问题是,当我运行它时,我的下拉列表看起来像这样 enter image description here 所以默认文本不会自动显示。 如果用户选择“选择许可证”并尝试提交表单,则会显示一个错误,说“选择许可证”,但它不会显示为默认文本。 我需要更改什么吗?

附:该图像是页面加载时的屏幕截图。默认情况下,将显示Trial作为选定的选项。

5个回答

90

尝试将LicenseTypesIndex0开始改为从1开始,如下所示:

public enum LicenseTypes
{
    Trial = 1,
    Paid = 2
}

然后你可以使用Range 属性来验证所选的许可证类型,就像下面这样:

public class YourViewModel
{
     //Other properties
     [Range(1,int.MaxValue,ErrorMessage = "Select a correct license")]
     public LicenseTypes LicenseTypes { get; set; }
}

最后,依照您的看法:

   @Html.EnumDropDownListFor(m => m.LicenseTypes,"Select a license",new { @class = "form-control"})
   @Html.ValidationMessageFor(m => m.LicenseTypes)

那个可以工作,但是它会将 选择许可证 添加为枚举值之一,其 ID 为 0。我希望能够在用户未从枚举中选择任何一个值时显示错误消息。 - Cybercop
我可以这样做,但我会暂时不接受它,看看是否有更好的解决方案出现,在此期间给你一个赞+1。 - Cybercop
3
@probackpacker的回答更好,这个选项不会被验证处理所捕获。 - Dan

75

当您的EnumDropDownListFor呈现时,SelectedLicense已经具有类型的默认值,即0

只需将SelectedLicense属性的类型更改为可空枚举,就像这样:

public LicenseTypes? SelectedLicense { get; set; }

这样做还可以让您继续使用Required属性,我认为这样更加简洁。 Required属性将不允许空响应,因此即使您的模型允许空值,表单也不会接受。


1
我认为这是今天最好的答案,但它似乎是一个hack。真正的解决方法应该在MVC内部处理非空枚举。 - jhilden
4
@jhilden,我认为MVC对非空枚举类型的处理是正确的,它完全按照您告诉它要做的来处理。在.NET中,枚举变量始终初始化为值0。假设您将属性类型保留为非空枚举(LicenseTypes),并且表单被提交时选择了“Select a License”(没有值的列表项),则您的SelectedLicense属性将最终具有默认值(Trial)。如果您只检查模型,则无法区分用户实际上是否选择了Trial值。 - Michael Richardson
你是正确的。我回顾了我的其他代码,如果我们想要一个 int 是必需的但没有默认值,那么我们可以这样做:[required] public int? NullableIntHere {get;set;} - jhilden

16

我有一个枚举:

public enum Sex
{
    Male,
    Female
}

在我的模型中,我有:

    [DisplayName("Sex")]
    [Required]
    public Sex? Sex { get; set; }

在视图中:

    @Html.EnumDropDownListFor(model => model.Sex, "Select sex", new { @class = "form-control", type = "text"})

通过这个下拉菜单,我有一个默认选项为“选择性别”,但验证仅接受枚举中提供的选项(“男”和“女”)。

在MVC3中(没有EnumDropDownListFor),我在模型中使用了:

    [DisplayName("Sex")]
    [Required(AllowEmptyStrings=false)]
    public Sex? Sex { get; set; }

    Sex = null;

    Sexes = Repository.GetAutoSelectList<Sex>("");

鉴于:

    @Html.DropDownListFor(model => model.Sex, Model.Sexes, new { @class = "form-control", type = "text" })

11

为了使 ViewModel 类的枚举属性成为默认选中项,需要在该枚举属性上设置默认值。

public class Test
    {
        public Cars MyCars { get; set; }
        public enum Cars
        {
            [Display(Name = @"Car #1")]
            Car1 = 1,
            [Display(Name = @"Car #2")]
            Car2 = 2,
            [Display(Name = @"Car #3")]
            Car3 = 3
        }

    }

控制器:

 public class EnumController : Controller
    {
        // GET: Enum
        public ActionResult Index()
        {
            var model = new Test {MyCars = Test.Cars.Car3}; // set default value
            return View(model);
        }
        [HttpPost]
        public ActionResult Index(Test model)
        {
            .....
        }
    }

查看:

@Html.BeginForm()
{
<div class="panel bg-white">
    <div class="panel-header fg-white">
        Enums
    </div>
    <div class="panel-content">
        <div class="input-control select size3">
            @Html.EnumDropDownListFor(model => model.MyCars)

        </div>
    </div>
    <input type="submit" class="button success large" />
</div>
}

0

我来晚了吗?

改变枚举类型的值并不是很令人满意。

将模型属性更改为可为空,然后添加 [Required] 属性以防止其为空也不是很令人满意。

我建议使用 ViewBag 来设置下拉列表的默认选定值。 控制器第 4 行是唯一重要的一行。

编辑:啊...新手...我的第一个想法是使用 ModelState.SetModelValue,因为我的新手本能阻止我简单地尝试在 ViewBag 中设置所需的值,因为下拉列表绑定到模型。我确信会有问题:它会绑定到模型的属性,而不是 ViewBag 的属性。我错了:ViewBag 是可以的。我已经纠正了代码。

这里是一个例子。

模型:

namespace WebApplication1.Models {

    public enum GoodMusic {
        Metal,
        HeavyMetal,
        PowerMetal,
        BlackMetal,
        ThashMetal,
        DeathMetal // . . .
    }

    public class Fan {
        [Required(ErrorMessage = "Don't be shy!")]
        public String Name { get; set; }
        [Required(ErrorMessage = "There's enough good music here for you to chose!")]
        public GoodMusic FavouriteMusic { get; set; }
    }
}

控制器:

namespace WebApplication1.Controllers {
    public class FanController : Controller {
        public ActionResult Index() {
            ViewBag.FavouriteMusic = string.Empty;
            //ModelState.SetModelValue( "FavouriteMusic", new ValueProviderResult( string.Empty, string.Empty, System.Globalization.CultureInfo.InvariantCulture ) );
            return View( "Index" );
        }
        [HttpPost, ActionName( "Index" )]
        public ActionResult Register( Models.Fan newFan ) {
            if( !ModelState.IsValid )
                return View( "Index" );
            ModelState.Clear();
            ViewBag.Message = "OK - You may register another fan";
            return Index();
        }
    }
}

视图:

@model WebApplication1.Models.Fan
<h2>Hello, fan</h2>
@using( Html.BeginForm() ) {
    <p>@Html.LabelFor( m => m.Name )</p>
    <p>@Html.EditorFor( m => m.Name ) @Html.ValidationMessageFor( m => m.Name )</p>
    <p>@Html.LabelFor( m => m.FavouriteMusic )</p>
    <p>@Html.EnumDropDownListFor( m => m.FavouriteMusic, "Chose your favorite music from here..." ) @Html.ValidationMessageFor( m => m.FavouriteMusic )</p>
    <input type="submit" value="Register" />
    @ViewBag.Message
}

如果在模型Index操作中没有"ModelState.SetModelValue或ViewBag.FavouriteMusic = string.Empty"行,则默认选择的值将是"Metal"而不是"Select your music..."


@shim:它可以在从主视图调用的部分视图中工作,但无法在通过AJAX调用的部分视图中工作。 部分视图会获得主视图ViewBag的副本。 当主视图调用部分视图时,您会执行Index操作。当AJAX请求调用部分视图时,则不会执行Index操作。Index.cshtml: - Rikou

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接