我有一个表格,每行都有一个下拉列表,如下所示:
@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
答案 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)