Question

I have been able to create viewmodel like this (please ignore that it includes another viewmodel, that will be fixed after I solve my current problem :) ):

public class UserViewModel
{
    #region Variables
    private SecUserViewModel user;
    private string[] assignedRolesIds;
    private List<SecRoleViewModel> availableRoles;
    #endregion

    #region Properties
    public SecUserViewModel User 
    { 
        get { return this.user; }
        set { this.user = value; }

    }
    public string Guid
    {
        get { return this.user.Guid.ToString(); }
        set { this.user.Guid = value; }
    }

    public string UserName
    {
        get { return this.user.UserName; }
        set { this.user.UserName = value; }
    }

    public string Email
    {
        get { return this.user.Email; }
        set { this.user.Email = value; }
    }

    public byte[] AuthDigest
    {
        get { return this.user.AuthDigest; }
        set { this.user.AuthDigest = value; }
    }

    public bool IsUsingTempPasswd
    {
        get { return this.user.IsUsingTempPasswd; }
        set { this.user.IsUsingTempPasswd = value; }
    }
    public DateTime? LastLogin
    {
        get { return this.user.LastLogin; }
        set { this.user.LastLogin = value; }
    }

    public DateTime? PasswordChanged
    {
        get { return this.user.PasswordChanged; }
        set { this.user.PasswordChanged = value; }
    }
    public string[] AssignedRolesIds
    {
        get { return this.assignedRolesIds; }
        set { this.assignedRolesIds = value; }

    }
    public List<SecRoleViewModel> AvailableRoles
    {
        get { return this.availableRoles; }
        set { this.availableRoles = value; }

    }
    #endregion

    #region Constructor

    public UserViewModel()
    {
        User = new SecUserViewModel();
        AssignedRolesIds = null;
        AvailableRoles = new List<SecRoleViewModel>(0);
    }

    public UserViewModel(SecUserViewModel secUser, List<SecRoleViewModel> roleList, List<SecRoleViewModel> availableList)
    {
        User = secUser;
        AssignedRolesIds = roleList.Select(r => r.Role.Guid.ToString()).ToArray();
        AvailableRoles = availableList;
    }

    #endregion
}

My controller has an edit action. On "GET" I pass viewmodel and it is displayed properly including the multiselect list and preselected values. But when I "POST" the "Edit", UserViewModel that is passed back has "AssignedRolesIds" and "AvailableRoles" Empty, although everything else is filled. When I check FormCollection object, there are "AssignedRolesIds" present as a key.

My view looks like this:

@model DocuLive.ViewModels.UserViewModel

@{
    ViewBag.Title = "Edit";
    Layout = "~/Views/Shared/_AdminPage.cshtml";
}

<h2>Edit</h2>
<div class="error-message">@TempData["Fail"]</div>
<div class="success-message">@TempData["Success"]</div>
@using (Html.BeginForm("Edit", "User", FormMethod.Post))
{
    @Html.AntiForgeryToken()
    @Html.ValidationSummary(true)

    <fieldset>
        <legend>SecUser</legend>

        <div class="editor-label">
            @Html.LabelFor(model => model.User.Guid)
        </div>
        <div class="editor-field">
            @Html.DisplayFor(model => model.User.Guid)
            @Html.HiddenFor(model => model.User.Guid)
        </div>
        <div class="editor-label">
            @Html.LabelFor(model => model.User.UserName)
        </div>
        <div class="editor-field">
            @Html.DisplayFor(model => model.User.UserName)
            @Html.HiddenFor(model => model.User.UserName)
        </div>
        <div class="editor-label">
            @Html.LabelFor(model => model.User.Email)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.User.Email)
            @Html.ValidationMessageFor(model => model.User.Email)
        </div>
        <div class="editor-label">
            @Html.LabelFor(model => model.User.IsUsingTempPasswd)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.User.IsUsingTempPasswd)
            @Html.ValidationMessageFor(model => model.User.IsUsingTempPasswd)
        </div>
        <div class="editor-label">
            @Html.LabelFor(model => model.User.LastLogin)
        </div>
        <div class="editor-field">
            @Html.DisplayFor(model => model.User.LastLogin)
        </div>
        <div class="editor-label">
            @Html.LabelFor(model => model.User.PasswordChanged)
        </div>
        <div class="editor-field">
            @Html.DisplayFor(model => model.User.PasswordChanged)
        </div>
        <div class="hidden-field">
            @Html.HiddenFor(model => model.User.AuthDigest)
        </div>
        <div class="editor-label">
            @Html.LabelFor(model => model.AssignedRolesIds)
        </div>
        <div class="editor-field">
            @Html.ListBoxFor(x => x.AssignedRolesIds, new MultiSelectList(Model.AvailableRoles, "Guid", "RoleName"), new { Multiple = "multiple", @class = "multi-select-list" }) 
        </div>
        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
}

<div>
    @Html.ActionLink("Back to List", "Users")
</div>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

Can anyone advise why only values related to ListBoxFor are not passed back (there is a null value)?

Thanks in advance

Was it helpful?

Solution

It seems that the problem is binding the string array values to string id value of complex object (in my case Role) - but I figured out a way around it eventually. The trick is to have this signature of the method:

[HttpPost]
public ActionResult Edit(UserViewModel user, string [] assignedRolesIds)

And then you have this in view:

@Html.ListBox("AssignedRolesIds",new MultiSelectList(Model.AvailableRoles, "Guid", "RoleName"),new { Multiple = "multiple", @class = "multi-select-list"})

With this solution, you have to reassign "assignedRolesIds" back to "AssignedRolesIds" property on UserViewModel, but that is only two lines (including check that the array is not emppty or null).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top