Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-mvc/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Asp.net mvc 用一个ASP.NETMVC下拉菜单编辑两个值的好方法是什么?_Asp.net Mvc_Asp.net Mvc 3_Model Binding_Hidden Field_Html.dropdownlistfor - Fatal编程技术网

Asp.net mvc 用一个ASP.NETMVC下拉菜单编辑两个值的好方法是什么?

Asp.net mvc 用一个ASP.NETMVC下拉菜单编辑两个值的好方法是什么?,asp.net-mvc,asp.net-mvc-3,model-binding,hidden-field,html.dropdownlistfor,Asp.net Mvc,Asp.net Mvc 3,Model Binding,Hidden Field,Html.dropdownlistfor,记录由其种类和记录ID唯一标识 我有一组要显示为下拉列表的记录,提交时我希望获得SelectedKind和SelectedRecordId,以便进一步处理 问题是,我希望单独处理这些值,但应该只有一个下拉列表 这样做的最佳实践是什么 我的建议是: 选择1 用字符串填充下拉列表,如“Kind\u RecordId”,并设置一个JavaScript更改处理程序,该处理程序将解析字符串并设置隐藏字段值。 然而,我不太喜欢在不同的地方有字符串操作逻辑的想法(在填充下拉列表时在控制器中,在解析值时在视图中

记录由其
种类
记录ID
唯一标识

我有一组要显示为下拉列表的记录,提交时我希望获得
SelectedKind
SelectedRecordId
,以便进一步处理

问题是,我希望单独处理这些值,但应该只有一个下拉列表
这样做的最佳实践是什么

我的建议是:

选择1 用字符串填充下拉列表,如
“Kind\u RecordId”
,并设置一个JavaScript
更改处理程序,该处理程序将解析字符串并设置隐藏字段值。

然而,我不太喜欢在不同的地方有字符串操作逻辑的想法(在填充下拉列表时在控制器中,在解析值时在视图中)。我是否应该将
SelectItem
填充逻辑也移动到视图中,并将业务对象保留在视图模型中

它还让我感到不安的是,在禁用JavaScript的罕见情况下,用户根本无法使用表单

选择2 在我的表单模型中公开一个唯一的
“Kind\u RecordId”
类字符串属性,并让模型通过控制器的强类型访问器属性对其进行解析(或填充)?

这似乎是一个更好的方法,但我不完全确定。我认为好的是它将保持视图模型中所有的解析/级联逻辑,并且当JavaScript不可用时它不会失败。
社区思想非常受欢迎。

一个优雅的方法是创建自己的类,并创建一个单独的类,将
记录ID
作为属性
。您需要使用属性为类指定模型绑定器,然后才能将该类用作操作方法参数

[ModelBinder (typeof (RecordIdentityBinder))]
public class RecordIdentity
{
    // Your types may be different
    public RecordKind Kind { get; set; }
    public int RecordId { get; set; }

    //TODO: replace this with your formatting algorithm
    public override string ToString ()
    {
        return string.Format ("{0}_{1}", Kind, RecordId);
    }

    //TODO: replace this with your parsing algorithm
    public static RecordIdentity Parse (string s)
    {
        string[] fragments = s.Split('_');

        if (fragments.Length != 2)
            return null;

        // Your object creation may be different
        return new MessagePartyIdentity {
            Kind = (RecordKind) Enum.Parse (typeof (RecordKind), fragments [0]),
            PartyID = int.Parse (fragments [1])
        };

    }
}

public class RecordIdentityBinder : IModelBinder
{
    public object BindModel (ControllerContext controllerContext, ModelBindingContext bindingContext)
    {            
        string key = bindingContext.ModelName;
        ValueProviderResult value = bindingContext.ValueProvider.GetValue (key);

        if (value == null || string.IsNullOrEmpty (value.AttemptedValue))
            return null;

        return RecordIdentity.Parse (value.AttemptedValue);
    }
}

public class MyController : Controller
{
    // ?identity=Foo_42 will become RecordIdentity { Kind = RecordKind.Foo, RecordId = 42 }
    public ActionResult DoSomethingWith (RecordIdentity selectedIdentity)
    {
        // ...
    }
}
在视图模板代码中,需要使用复合属性调用
Html.DropDownListFor()

@Html.DropDownListFor(m => m.SelectedIdentity, Model.RowList)
对于
行列表
中的每个值或您称之为数据源的任何值,确保
SelectListItem
属性设置为您的类“
ToString()
输出。

Html.DropDownListFor
中指定的对象的
RecordIdentity
类型属性的名称应与操作参数名称匹配。否则,您需要在的
Prefix
属性中指定下拉名称,如下所示:

另请注意,如果希望
RecordIdentity
成为表单模型的属性,或者希望接受作为动作方法参数的任何类,则该方法也会起作用。
绑定器将以任何方式调用


通过采用这种方法,您可以使单个类负责格式化和解析,这在很大程度上是不可见的,并且提供了对实际字段的抽象。然而,我需要注意的是,这样的问题也可能是由糟糕的数据库或业务实体组织造成的。也许更好的解决方案是为列出的每个项提供其唯一的本机密钥。

我认为最好定义一个具有2个属性的新类。类似于:

public class KindRecordItem {
    public int Id {get; set;}
    public string Kind {get; set;}
    public int RecordId {get; set;}
    public string Text {get; set;}
}
将所有有效/合法的种类和recordId组合生成一个集合,将该集合传递给视图,并在下拉列表中显示显示文本

<%= Html.DropDownListFor(m => m.SelectedKindRecordItem, 
        new SelectList(Model.KindRecordItems, "Id", "Text"),
        new SelectListItem { Value = "0", Text = "Please select an option" }) %>
m.SelectedKindRecordItem,
新建SelectList(Model.KindRecordItems、“Id”、“文本”),
新建SelectListItem{Value=“0”,Text=“请选择一个选项”})%>
在控制器中,SelectedKindRecordItem将是一个唯一的ID,您可以查找该ID以查找要处理的种类和记录ID


Id可以生成为Kind和RecordId的散列或任何其他方法以使其唯一。

那么用户将从Kind和RecordId的任意组合中进行选择吗?也就是说,如果有3种类型和4个记录ID,他们可以从12个下拉项中选择?不,根本不会有两个不同的列表。你可以把它看作一个复合键,这就是我的意思。1个下拉列表,包含12项。它是每种类型和记录ID的组合在一个下拉列表中。正确吗?不。更接近真实世界:用户可以向其他用户或商店发送消息。因此,实体ID将有一个属性,实体种类将有一个属性。这并不过分,因为还有其他类型的实体可以接收消息,而且它们都有自己的表。用户可以为
To
字段选择任何目标用户/商店/任何东西,但是让用户手动选择种类和ID没有任何意义。我的意思是可以有6个选项,例如4个用户和2个商店。或5个商店和一个用户。或者他们都可以是用户。。这取决于数据库中的数据。这从来不是“每种组合”类型的事情。谢谢你的输入。这看起来是一个很酷的方法,所以我会尝试一下,让你知道。至于实体组织,这些实体实际上来自不同的表,它们只有在非常特定的情况下才有意义。这就是为什么我决定用这样的“复合键”来描述它们。我不确定BindModel方法的代码是否正确工作,但如果您执行所有其他建议操作来激活此绑定器,您可以在创建的基础结构上调试它,并告诉我,如果有什么不正确的地方。这是一个完美的解决方案,非常感谢。我刚刚用100%工作代码和一个小的添加更新了你的答案。你能检查一下
Bind
属性部分的正确性吗?我试图提供一个真实的示例,但我不是100%正确。@gaearon,好的,我今天将检查它是否完全可靠,但模型绑定机制仅基于通过POST传递的表单集合的名称和值。如果您使用props和另一个参数名绑定简单类,它将成功填充,因为
<%= Html.DropDownListFor(m => m.SelectedKindRecordItem, 
        new SelectList(Model.KindRecordItems, "Id", "Text"),
        new SelectListItem { Value = "0", Text = "Please select an option" }) %>