为什么我的DropDownList没有绑定到我的模型?

时间:2014-07-24 17:20:15

标签: asp.net-mvc vb.net entity-framework-6 model-binding html.dropdownlistfor

视图模型:

Public Class UserViewModel
<Display(Name:="Roles List")> _
Public ReadOnly Property AllRoles As IEnumerable(Of SelectListItem)
    Get
        Dim dbContext As New AuthUserContext
        Dim roleQuery = (From r In dbContext.AuthRoleSet Select r Where r.isActive = True)
        Dim roles As IEnumerable(Of AuthRole) = roleQuery.ToList()
        Return roles.Select(Function(o) New SelectListItem() With {.Text = o.RoleName, .Value = o.AuthRoleID})
    End Get
End Property
Public Property User As New AuthUser
End Class

我的AuthUser课程:

Public Class AuthUser

'Properties
Public Property AuthUserID() As Integer

<Required()> _
<Display(Name:="User Name")> _
Public Property UserName() As String

<Required()> _
<Display(Name:="Current Roles")> _
Public Overridable Property AuthRoles As ICollection(Of AuthRole)

End Class

Public Class AuthRole
Public Property AuthRoleID() As Integer

<Required()> _
<Display(Name:="Role Name")> _
Public Property RoleName() As String

<Required()> _
<Display(Name:="Is Active")> _
Public Property isActive() As Boolean

Public Overridable Property AuthUser As ICollection(Of AuthUser)

End Class

我的控制器:

Function CreateUser() As ActionResult
    Dim model As New UserViewModel
    Return View(model)
End Function

我的帖子控制器:

Function CreateUser(ByVal authuser As UserViewModel) As ActionResult
    If ModelState.IsValid Then
        db.AuthUserSet.Add(authuser.User)
        db.SaveChanges()
        Return RedirectToAction("Index")
    End If

    Return View(authuser)
End Function

我的观点:

@Using Html.BeginForm()
@Html.ValidationSummary(True)
@Html.AntiForgeryToken()

@<fieldset>
    <legend>AuthUser</legend>

   <div class="editor-label">
        @Html.LabelFor(Function(model) model.User.UserName)
    </div>
    <div class="editor-field">
        @Html.TextBoxFor(Function(model) model.User.UserName)
        @Html.ValidationMessageFor(Function(model) model.User.UserName)
    </div>

    <div class="editor-label">
        @Html.LabelFor(Function(model) model.User.AuthRoles)
    </div>
    <div class="editor-field">
       @Html.DropDownListFor(Function(model) model.User.AuthRoles, Model.AllRoles, "-- Select Role--")
       @Html.ValidationMessageFor(Function(model) model.User.AuthRoles)
    </div>

    @*Have to fill this is for ModelState validation - via jQuery*@
    @Html.HiddenFor(Function(model) model.User.AuthRoles)

    <p>
        <input type="submit" value="Create" />
    </p>
</fieldset>
End Using

好吧,我在这里做的就是将我所有可用的角色都读到我的ViewModel中。我想将它们列为下拉列表,并使用从那里选择的AuthRoleID来确定在我的模型中分配哪个角色。

我的AuthRoles属性在我的帖子中总是空的。我的观点全部正确显示。

我在这里使用EF6,Code First。

2 个答案:

答案 0 :(得分:1)

我还不能发表评论,但我的第一个问题是DropDownList?您正在尝试将ICollection(Of AuthRole)绑定到int类型的选定值,您将只能选择一个值,而不是列表。您需要一个不同的控件,如ListBox。但是要选择一个角色:

添加属性SelectedRole ...

Public Class UserViewModel
<Display(Name:="Roles List")> _
Public ReadOnly Property AllRoles As IEnumerable(Of SelectListItem)
    Get
        Dim dbContext As New AuthUserContext
        Dim roleQuery = (From r In dbContext.AuthRoleSet Select r Where r.isActive = True)
        Dim roles As IEnumerable(Of AuthRole) = roleQuery.ToList()
        Return roles.Select(Function(o) New SelectListItem() With {.Text = o.RoleName, .Value = o.AuthRoleID})
    End Get
End Property
Public Property SelectedRole As Integer //for the drop down list to bind selected value to//
Public Property UserName As String //all you need for the view model
Public Property UserId as String //hidden value in the view when you come to edit the user and post it back to the controller
End Class

在您的视图中,将下拉列表更改为:

<div class="editor-field">
   @Html.DropDownListFor(Function(model) model.SelectedRole, Model.AllRoles, "-- Select Role--")
   @Html.ValidationMessageFor(Function(model) model.SelectedRole)
</div>

在视图中添加此隐藏字段:

  @Html.HiddenFor(Function(model) model.Id)

您的创建获取方法:

Function CreateUser() As ActionResult
    Dim model As New UserViewModel
    Return View(model)
End Function

您的编辑获取方法

Function EditUser(id as string) As ActionResult
    //logic to test if Id is empty if not fetch user from dB as variable user
    //Dim user as New AuthUser... etc
    Dim model As New UserViewModel
    model.SelectedRole = user.AuthRole // assuming one role as you are using DropDownList - you would need to use a different Editor to multi select roles and thus change the logic to get a list of roles
    model.UserName = user.UserName
    model.Id = user.Id
    Return View(model)
End Function

然后您的创建帖子控制器可以设置角色

Function CreateUser(ByVal model As UserViewModel) As ActionResult
    If ModelState.IsValid Then
        //logic to update role from authUser.SelectedRole
        Dim authuser As New AuthUser
        //update properties of authuser from the model
        authuser.UserName = model.UserName // etc.
        //
        db.AuthUserSet.Add(authuser.User)
        db.SaveChanges()
        Return RedirectToAction("Index")
    End If
//something went wrong
Return View(model)
End Function

for Edit Post方法:

Function EditUser(ByVal model As UserViewModel) As ActionResult
    If ModelState.IsValid Then
        //logic to update role from authUser.SelectedRole
        //Fetch user from the dB using the hidden field model.Id
        //update properties of fetched user from the model
        authuser.UserName = model.UserName // etc.
        //

        db.SaveChanges()
        Return RedirectToAction("Index")
    End If
//something went wrong
Return View(model)
End Function

我没有对上述内容进行测试,习惯了c#,但希望你能得到这个想法。

根据评论对ViewModel添加进行了编辑。您可以为Create和Edit创建一个单独的视图,从而分离ViewModels - 但实质上是确保ViewModel完全不知道实体的良好实践,反之亦然

答案 1 :(得分:0)

您的AuthRoles属性需要类型为AuthRole的对象,而您要回发Integer列表。换句话说,您无法直接发回此集合属性。相反,您需要另一个属性,例如:

Public Property SelectedAuthRoles As List(Of Integer)

然后,使用它从数据库中查找AuthRoles这些ID,最后将AuthRole添加到AuthRoles属性。

(我的VB非常缺乏,因为我几乎完全使用C#,所以如果上面的属性不太正确,我会道歉。尽管如此,它应该足以至少传达这个想法。)