简体   繁体   English

如何确定选定的值在asp.net MVC视图中的下拉列表?

[英]How to determine selected value for drop down lists in asp.net MVC View?

New to asp.net MVC. asp.net MVC的新功能。 I have a table that has multiple fields. 我有一个包含多个字段的表。 I want to build input rules where the user has to select a value either in Field1's or Field2's drop down list. 我想建立输入规则,用户必须在其中选择Field1或Field2的下拉列表中的值。 The user will not be able to post if a value is selected for both Field1 and Field2 simultaneously or if neither Field1 or Field2 have a selected value. 如果同时为Field1和Field2选择了一个值,或者Field1或Field2都没有选择的值,则用户将无法发布。

Part of my dilemma is in deciding where the input logic or rules should be recorded (Controller vs View)? 我的两难选择是决定应该在哪里记录输入逻辑或规则(Controller vs View)? As I understand it, best practice is to keep the Controller simple and "skinny" so do I place the input rules in the View using Razor? 据我了解,最佳实践是保持Controller简单而“瘦”,那么我是否可以使用Razor在View中放置输入规则? If so, how? 如果是这样,怎么办?

Thank you in advance for your suggestions. 预先感谢您的建议。

Here is the model: 这是模型:

public class Order
{
    public int OrderID {get; set;} 
    public string Field1 {get; set;} 
    public string Field2 {get; set;} 
    //other properties 
}                                                        

I use viewbags in the Controller to create the dropdownlists: 我在Controller中使用viewbag创建下拉列表:

// GET: Order/Create
public ActionResult Create()
{
     ViewBag.Field1 = new SelectList(db.Field1.OrderBy(x => x.Name), "Name", "Name");            
     ViewBag.Field2 = new SelectList(db.Field2.OrderBy(z => z.Clip), "Clip", "Clip");            
     return View();
}

View: 视图:

<div class="form-group">
     @Html.LabelFor(model => model.Field1, htmlAttributes: new { @class = "control-label col-md-2" })
     <div class="col-md-10">
         @Html.DropDownListFor(model => model.Field1, (SelectList)ViewBag.Field1, "Select one...", htmlAttributes: new { @class = "form-control" })
         @Html.ValidationMessageFor(model => model.Field1, "", new { @class = "text-danger" })                
      </div>
</div>                                                               
<div class="form-group">
     @Html.LabelFor(model => model.Field2, htmlAttributes: new { @class = "control-label col-md-2" })
     <div class="col-md-10">
         @Html.DropDownListFor(model => model.Field2, (SelectList)ViewBag.Field2, "Select one...", htmlAttributes: new { @class = "form-control" })
         @Html.ValidationMessageFor(model => model.Field2, "", new { @class = "text-danger" })                
     </div>
 </div> 

You can do the following. 您可以执行以下操作。 I explain in the code where to put each item: 我在代码中解释了将每个项目放在哪里:

View: 视图:

@*put model reference here*@
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>IndexValid9</title>
</head>
<body>
    @using (Html.BeginForm())
    {
        <table>
            <tr>
                <td>
                    @Html.DropDownListFor(m => m.SelectedA,
                new SelectList(Model.TableAList, "Value", "Text"))
                    @Html.ValidationMessageFor(model => model.SelectedA)
                </td>
            </tr>
            <tr>
                <td>
                    @Html.DropDownListFor(m => m.SelectedB,
                new SelectList(Model.TableAList, "Value", "Text"))
                    @Html.ValidationMessageFor(model => model.SelectedB)
                </td>
            </tr>
        </table>
        <input type="submit" value="submit" />
    }
</body>
</html>

Controller Model 控制器型号

//You can put this in a model folder
public class FieldViewModel
{
    public FieldViewModel()
    {
        TableAList = Utilites.GetTableAList();
        TableBList = Utilites.GetTableBList();
    }

    public List<SelectListItem> TableAList { get; set; }
    public List<SelectListItem> TableBList { get; set; }
    public int SelectedA { get; set; }
    public int SelectedB { get; set; }
}

//You can put this in its own folder
public class Utilites
{
    public static List<SelectListItem> GetTableAList()
    {
        List<SelectListItem> list = new List<SelectListItem>();

        try
        {
            using (BreazEntities31 entity = new BreazEntities31())
            {
                entity.TableAs.
                    OrderBy(r => r.Text).ToList().ForEach(r => list.Add(
                    new SelectListItem { Text = r.Text, Value = r.Value.ToString() }));
            }
        }
        catch (Exception e)
        { }

        //add <select> to first item
        list.Insert(0, new SelectListItem { Text = "", Value = "" });

        return list;
    }

    public static List<SelectListItem> GetTableBList()
    {
        List<SelectListItem> list = new List<SelectListItem>();

        try
        {
            using (BreazEntities31 entity = new BreazEntities31())
            {
                entity.TableBs.
                    OrderBy(r => r.Text).ToList().ForEach(r => list.Add(
                    new SelectListItem { Text = r.Text, Value = r.Value.ToString() }));
            }
        }
        catch (Exception e)
        { }

        //add <select> to first item
        list.Insert(0, new SelectListItem { Text = "", Value = "" });

        return list;
    }
}

public class HomeController : Controller
{
    [HttpPost]
    public ActionResult IndexValid9(FieldViewModel fieldViewModel)
    {
       //put breakpoint here to see selected values from both ddl, interrogate fieldViewModel
       return View();
    }

    public ActionResult IndexValid9()
    {
        FieldViewModel fieldViewModel = new FieldViewModel();
        return View(fieldViewModel);
    }

Tables: 表:

CREATE TABLE [dbo].[TableA](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [Text] [varchar](20) NULL,
    [Value] [int] NULL,
 CONSTRAINT [PK_TableA] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
SET ANSI_PADDING OFF
GO
/****** Object:  Table [dbo].[TableB]    Script Date: 6/27/2017 3:59:07 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[TableB](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [Text] [varchar](20) NULL,
    [Value] [int] NULL,
 CONSTRAINT [PK_TableB] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
SET ANSI_PADDING OFF
GO
SET IDENTITY_INSERT [dbo].[TableA] ON 

GO
INSERT [dbo].[TableA] ([Id], [Text], [Value]) VALUES (1, N'tableaTxt', 1)
GO
INSERT [dbo].[TableA] ([Id], [Text], [Value]) VALUES (2, N'tableaTxt2', 2)
GO
SET IDENTITY_INSERT [dbo].[TableA] OFF
GO
SET IDENTITY_INSERT [dbo].[TableB] ON 

GO
INSERT [dbo].[TableB] ([Id], [Text], [Value]) VALUES (1, N'tablebTxt', 1)
GO
INSERT [dbo].[TableB] ([Id], [Text], [Value]) VALUES (2, N'tablebTxt2', 2)
GO
SET IDENTITY_INSERT [dbo].[TableB] OFF
GO

Validation logic is usually implemented in the View Model class using data annotations. 验证逻辑通常是在View Model类中使用数据注释实现的。 However for your case you can use a custom validation attribute like the following 但是,对于您的情况,您可以使用以下自定义验证属性

    public class OnlyOneValueAttribute : ValidationAttribute
    {
        public string TheOtherPropertyName { get; private set; }

        public OnlyOneValueAttribute(string theOtherPropertyName)
        {
            TheOtherPropertyName = theOtherPropertyName;
        }

        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            var theProperty = validationContext.ObjectType.GetProperty(validationContext.MemberName);
            var theValue = theProperty.GetValue(validationContext.ObjectInstance, null) as string;

            var theOtherProperty = validationContext.ObjectType.GetProperty(TheOtherPropertyName);
            var theOtherValue = theOtherProperty.GetValue(validationContext.ObjectInstance, null) as string;

            if (string.IsNullOrEmpty(theValue) && !string.IsNullOrEmpty(theOtherValue) || !string.IsNullOrEmpty(theValue) && string.IsNullOrEmpty(theOtherValue))
            {
                return ValidationResult.Success;
            }
            return new ValidationResult(ErrorMessage);
        }
    }

You can then use it in your model 然后可以在模型中使用它

    public class Order
    {
        public int OrderID { get; set; }
        [OnlyOneValue(nameof(Field2))]
        public string Field1 { get; set; }
        [OnlyOneValue(nameof(Field1))]
        public string Field2 { get; set; }
        //other properties 
    }

And in your controller you test on you model state validity 然后在控制器中测试模型状态有效性

        [HttpPost]
        public ActionResult Test(Order model)
        {
            if (ModelState.IsValid)
            {
                //OK logic
            }
            return View();
        }

However I suggest you review the implementation of this use case for UX convenience. 但是,为了方便UX,建议您回顾此用例的实现。

Hope this helps. 希望这可以帮助。

If the validation rule is a part of business logic/requirement then it should be implemented in the backend/server side. 如果验证规则是业务逻辑/需求的一部分,则应在后端/服务器端实现。 Remember that users can post data to your routes using tools like postman etc, hence bypassing your UI/View validation. 请记住,用户可以使用邮递员等工具将数据发布到您的路线,从而绕过您的UI / View验证。 Javascript/UI validation to show/hide input is an extra step that you can take to make it easier for your users. 显示/隐藏输入的Javascript / UI验证是您可以采取的额外步骤,以使用户更轻松。 If this validation only occurs at one place of your application, I'd keep it simple, stupid (KISS) and just validate inside a controller: 如果此验证仅在应用程序的某个位置进行,我将使其简单,愚蠢(KISS)并仅在控制器内部进行验证:

[HttpPost]
public ActionResult Create(OrderViewModel order)
{
    var bothFieldsAreEmpty = string.IsNullOrEmpty(order.Field1) && string.IsNullOrEmpty(order.Field2);
    var bothFieldsAreFilled = !string.IsNullOrEmpty(order.Field1) && !string.IsNullOrEmpty(order.Field2);

    if (bothFieldsAreEmpty || bothFieldsAreFilled)
    {
        ModelState.AddModelError("", "Please select either Field1 or Field2, not both.");
    }
    if (ModelState.IsValid)
    {
    // Do something
    }
    return View(order);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 ASP.NET MVC 2-如何从下拉菜单中获取选定的值? - ASP.NET MVC 2 - How can I get the selected value from a drop down into my view model? 如何动态创建下拉列表并在视图中枚举? asp.net MVC 5 - How to dynamically create drop down lists and enumerate them at view? asp.net MVC 5 如何在asp.net mvc3中获取下拉列表的选定值? - how to get selected value of drop down list in asp.net mvc3? ASP.Net MVC 查看页面顺序下拉列表不起作用 - ASP.Net MVC View Page Sequential drop down lists not working ASP.NET MVC 2筛选多个下拉列表 - ASP.NET MVC 2 Filtering multiple drop down lists ASP.NET Core 2 MVC选择标记帮助器(下拉列表)所选项目并非总是反映值 - ASP.NET Core 2 MVC Select Tag Helper (drop-down) Selected Item Not Always Reflecting Value 网格视图中的 asp.NET 下拉列表 - 获取选定的值 - asp.NET Drop Down List within a Grid View - Getting the selected value asp.net:设置为下拉列表选择的默认值 - asp.net : set default value selected for a drop down list 无法在asp.net的下拉列表中显示选定的值 - Not able to display selected value in drop down list in asp.net 如何在c#asp.net中动态绑定具有3个下拉列表的网格视图? - How would I dynamically bind a grid view with 3 drop down lists in c# asp.net?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM