如何使DropDownListFor使用项目ID而不是索引?

时间:2016-04-28 12:36:16

标签: asp.net-mvc

我有一个表格,每行都有一个下拉列表,如下所示:

@Html.DropDownListFor(m => m.Transactions[i].CategoryID, ...)

一切都很有效。我可以选择项目,提交表单,模型有我更新的选择。到目前为止一切都很好。

问题是这不是很可靠。由于每个下拉列表的名称都基于索引而不是ID,这意味着post值与生成在数据库中的实际项目之间的匹配基于索引。大部分时间都可以正常工作,但是如果项目列表在页面加载时间和用户进行回发之间发生变化会怎样?索引已经改变,这意味着后期数据不能正确匹配,并且会发生不好的事情。或者我已经看到浏览器错误地尝试在帖子之间的下拉列表中保留选择,但是因为项目列表正在改变(在页面刷新时可能是项目#2现在可能是项目#3)并且所有内容都基于在指数上,错误的下拉列表会得到错误的值。

基本上,我如何强制下拉列表生成一个看起来更像这样的名称和ID:

Transactions_CategoryID_12385652 // 12385652 is the CategoryID

而不是:

Transactions_4_CategoryID // 4 is the array index

并且仍然具有自动绑定的好处?

编辑:我提到的第二个问题(刷新后输入值被错误地恢复)似乎只发生在Firefox上。 https://bugzilla.mozilla.org/show_bug.cgi?id=46845

2 个答案:

答案 0 :(得分:0)

您必须编写自己的自定义模型绑定器以及Html扩展以通过这种方式生成元素名称,或者您可以使用Razor手动生成标记。

您是否有特殊需要这样做?你几乎总是遵循框架的约定,除非有充分的理由不这样做。

答案 1 :(得分:0)

您可以将所需的确切集合传递给视图,并将其绑定到DropDownFor html帮助器。

假设你有一个人。

Sub PerformTheActions()
    Dim oDictionary As Object

    Set oDictionary = CreateObject("Scripting.Dictionary")

    AddToDictionary oDictionary, Sheet1.Range("A1:A33")

    va = ReturnTopNValuesFromDict(oDictionary, 10)

    For i = LBound(va) To UBound(va)
        MsgBox "Key: " & va(i, 1) & " Value: " & va(i, 2)
    Next i

End Sub

' Below is just a helper function to add a bunch of numbers into a dictionary
' You won't need to use it because you likely have other business logic to create your dict
Private Sub AddToDictionary(odict As Object, rng As Range)
    Dim cel As Range
    Dim nID As Integer

    nID = 1
    For Each cel In rng
        If Not odict.exists(cel.Value) Then
            odict.Add nID, cel.Value
            nID = nID + 1
        End If
    Next cel

End Sub

Private Function ReturnTopNValuesFromDict(odict As Object, nTop As Integer) As Variant()
    Dim topN() As Variant
    Dim nCounter As Integer
    Dim vCutoff As Variant
    Dim nCutoffIndex As Long

    ReDim topN(1 To nTop, 1 To 2)
    nCounter = 1

    For Each oitem In odict
        If nCounter <= nTop Then
            topN(nCounter, 1) = oitem
            topN(nCounter, 2) = odict(oitem)
            nCounter = nCounter + 1
        Else
            vCutoff = topN(LBound(topN), 2)
            nCutoffIndex = LBound(topN)

            For i = LBound(topN) + 1 To UBound(topN)
                If topN(i, 2) < vCutoff Then
                    vCutoff = topN(i, 2)
                    nCutoffIndex = i
                End If
            Next i

            If vCutoff > odict(oitem) Then
                'Do nothing because lowest value in array is greater than this item
            Else
                topN(nCutoffIndex, 1) = oitem
                topN(nCutoffIndex, 2) = odict(oitem)
            End If
        End If
    Next oitem
    BubbleSortArray topN
    ReturnTopNValuesFromDict = topN
End Function

Private Function BubbleSortArray(vArray As Variant) As Variant()
    Dim vPlaceHolder As Variant
    Dim nFirst As Long
    Dim nSecond As Long


    For nFirst = LBound(vArray) To UBound(vArray)
        For nSecond = nFirst + 1 To UBound(vArray)
            If vArray(nFirst, 2) < vArray(nSecond, 2) Then
                vPlaceHolder = vArray(nFirst, 1)
                vArray(nFirst, 1) = vArray(nSecond, 1)
                vArray(nSecond, 1) = vPlaceHolder

                vPlaceHolder = vArray(nFirst, 2)
                vArray(nFirst, 2) = vArray(nSecond, 2)
                vArray(nSecond, 2) = vPlaceHolder
            End If
        Next nSecond
    Next nFirst
End Function

你想要添加一个新人。创建视图模型。在此ViewList类型的视图模型中创建属性。此选择列表将包含要使用。

填充下拉列表的模型集合
public class Person
{
    public int Id { get; set; }
    public int Name { get; set; }
}

假设您希望下拉列表将Person's Id作为选定值并将Person名称作为文本值。您可能希望创建第二个视图模型来表示该模型或使用匿名对象。我们来调用集合myCollection。并且假设该集合由具有两个属性(以及Id和Name属性)的对象组成。现在只需使用MySelectList的值传递此视图模型。

public class PersonViewModel
{
    public int Id { get; set; }
    public string Name { get; set; }
    public SelectList MySelectList { get; set; }
}

在你的剃刀视图中你可以这样设置@ Html.DropDownListFor:

var viewModel = new MyViewModel 
{
    MySelectList = new SelectList(myCollection, "Id", "Name")
};

为了将select值传递给下拉列表的视图,只需使用允许传递此值的SelectList构造函数重载:

@Html.DropDownListFor(m => m.Id, Model.MySelectList)