20
  • VS2012, .NET 4.51

I have a user control that contains a ListView that is using model binding. So far so good. I want to display a list of objects based on how the user has manipulated the view mode. To this end I have a public property called Roles. However when I call TryUpdateModel() from inside there, I receive the exception:

TryUpdateModel' must be passed a value provider or alternatively must be invoked from inside a data-operation method of a control that uses model binding for data binding

Now while I understand I can drop out of edit mode by doing:

lvData.EditIndex = -1;

and then in the UpdateMethod call TryUpdateModel(), I was wondering how I could call TryUpdateModel without having to wire up the method to do the update. To put it another way how/where/what do I supply for the IValueProvider parameter to TryUpdateModel().

/// <summary>
///     Initialise the user control
/// </summary>
/// <param name="aRoles">List of roles to display</param>
public void Activate(List<RoleInfo> aRoles)
{
    //List we will be binding
    _ViewModel = new List<MembershipRolesViewModel>();

    //Transfer the supplied list into the view model
    foreach (RoleInfo roleInfo in aRoles)
    {
        _ViewModel.Add(new MembershipRolesViewModel
        {
            RoleDisplayName = roleInfo.RoleDisplayName,
            RoleHint = roleInfo.RoleHint,
            RoleName = roleInfo.RoleName,
            RoleSelected = roleInfo.RoleSelected
        });
    }
}

//ListView.SelectMethod points here
public IQueryable<MembershipRolesViewModel> RolesSelect()
{
    return _ViewModel.AsQueryable();
}

//Property to return the roles as manipulated by the user
public List<RoleInfo> Roles
{
    get
    {
        List<RoleInfo> result = new List<RoleInfo>();
        TryUpdateModel(_ViewModel);

        foreach (MembershipRolesViewModel membershipRolesViewModel in _ViewModel)
        {
            result.Add(new RoleInfo
            {
                RoleDisplayName = membershipRolesViewModel.RoleDisplayName,
                RoleHint = membershipRolesViewModel.RoleHint,
                RoleName = membershipRolesViewModel.RoleName,
                RoleSelected = membershipRolesViewModel.RoleSelected
            });
        }

        return result;
    }
}

TryUpdateModel must be passed a value provider or alternatively must be invoked from inside a data-operation method of a control that uses model binding for data binding.

curls
  • 382
  • 1
  • 3
  • 16
TheEdge
  • 9,291
  • 15
  • 67
  • 135
  • I tried `TryUpdateModel(_viewModel, new FormValueProvider(Page.ModelBindingExecutionContext));` with no success. It runs, and the `FormValueProvider` correctly parses the form values.... but `TryUpdateModel` does not copy them to the corresponding viewModel properties. – Merenzo Feb 14 '14 at 01:51
  • I can see you're simply populating a ViewModel for use with a view. There is no action method or cshtml reference mentioned. What exactly are you trying to achieve with TryUpdateModel() as thats nothing but an explicit call to the ModelBinder. And there is no IValueProvider in sight here. Refer to this if you are looking for more info on updating model: http://stackoverflow.com/questions/5268421/when-and-why-do-you-use-tryupdatemodel-in-asp-net-mvc-2 – Vaibhav Mar 18 '14 at 19:19
  • Any chance of an example of some working **WebForms** code? – TheEdge Apr 14 '14 at 22:10
  • 1
    More code is required to understand what is going on here in context of the problem. can you paste the whole class? – G.Y May 12 '14 at 15:22
  • I can't even figure out what `TryUpdateModel` is since you don't show what class you are in. http://sscce.org – Aron May 13 '14 at 09:47
  • @Aron - http://blog.pluralsight.com/asp-net-4-5-web-forms-features-model-binding, http://weblogs.asp.net/scottgu/archive/2011/10/30/web-forms-model-binding-part-3-updating-and-validation-asp-net-4-5-series.aspx, http://msdn.microsoft.com/en-us/library/system.web.ui.page.tryupdatemodel(v=vs.110).aspx – TheEdge May 13 '14 at 23:10

2 Answers2

1

There's no simple way to get values from ListView items. You have to loop on items and extract their values.

var bindableTemplate = lv.ItemTemplate as IBindableTemplate;
foreach (ListViewItem item in lv.Items)
{
    var dic = bindableTemplate.ExtractValues(item).Cast<System.Collections.DictionaryEntry>().ToDictionary(k => (string)k.Key, v => v.Value);
    var provider = new DictionaryValueProvider<object>(dic, System.Globalization.CultureInfo.InvariantCulture);

    // Now we can update the item.
    TryUpdateModel<RoleInfo>(model, provider);
}

Or force the ListView to update own item.

public List<RoleInfo> Roles
{
    get
    {
        List<RoleInfo> result = new List<RoleInfo>();
        for (int i = 0; i < lv.Items.Count; i++)
            if (lv.Items[i].ItemType == ListViewItemType.DataItem)
                lv.UpdateItem(i, true);

        //...

        return result;
    }
}



public void lv_UpdateItem(int id)
{
    RoleInfo model = //...
    TryUpdateModel(model);
}

Hope this helps.

cem
  • 1,911
  • 12
  • 16
0

Calling TryUpdateModel outside an Action method that is wrong way to do. Because Model Binder tightly coupled with the Action method so that they can auto populate to model properties with data whatever we have filled on the UI.

So, please try to TryUpdateModel within an action method,I hope that will work fine.

RajeshVerma
  • 1,087
  • 9
  • 13