开发者

Extracting [] elements from form collection - mvc - should use icollection but have mix of types

have looked at Phil Haacks project on books at

http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx

which has been useful, but I have a mix of data types.

I use a modelview so that i can have a mix of objects, in this case: Order (ie order.id, order.date etc), Customer, SoilSamplingOrder and a list of SoilSamplingSubJobs which is like this [0].id, [0].field, [1].id, [1].field etc Perhaps I should be using ICollection instead of List? I had problems getting UpdateModel to work so I used an extract from collection method. the first 4 method calls : orderRe开发者_StackOverflowpository.FindOrder(id); etc give the model the original to be edited. but after this point i'm a little lost in how to update the subjobs. I hope i have delineated enough to make sense of the problem.

 [HttpPost]
        public ActionResult Edit(int id, FormCollection collection)
        {

            Order order = orderRepository.FindOrder(id);
            Customer cust = orderRepository.FindCustomer(order.customer_id);
            IList<SoilSamplingSubJob> sssj = orderRepository.FindSubOrders(id); 
            SoilSamplingOrder sso = orderRepository.FindSoilSampleOrder(id);

            try
            {

                UpdateModel(order, collection.ToValueProvider());

                UpdateModel(cust, collection.ToValueProvider());

                UpdateModel(sso, collection.ToValueProvider());



                IList<SoilSamplingSubJob> sssjs = orderRepository.extractSSSJ(collection);

                foreach (var sj in sssjs)
                    UpdateModel(sso, collection.ToValueProvider());


                orderRepository.Save();

                return RedirectToAction("Details", new { id=order.order_id});

            }
            catch
            {
                return View();
            }
        }


I think you should work on developing a view model that reflects the data that you need to get back and create display/edit templates for that model that renders the view model using Phil Haack's methods for your lists of objects -- in this case, arrays of submodel classes. Let the model binding framework build the returned model (as a parameter) to your action, then reconstitute your domain models from the view model data. Brad Wilson has an excellent series of articles on templating that should be helpful.


I use IModelBinder on my complex classes. You don't need IModelBinder, but it will make your controller post codeblock look much cleaner. I'm using VB at the moment, but my class looks something like this for example:

 Public Class CombinedRulesAndXmlRules : Implements IModelBinder
    Public Rules As New Rules()
    Public XmlRules As New XmlRules()
    Public RequiredTemplates As New List(Of RequiredTemplates)
    Public SearchCriteria As New List(Of SearchCriteriaList)
    Public OptionalTemplates As New List(Of OptionalTemplates)
    Public Questions As New List(Of Questions)
    Public QATemplates As New List(Of QATemplates)
    **Public Answers As New List(Of Answers)**

Now I don't use editor templates in my views, so to have your lists appear in the formcollection you have to add something like this in your view:

 @For x As Integer = 0 To Model.Answers.Count - 1
            Dim incr As Integer = x
        @Html.HiddenFor(Function(model) model.Answers(incr).Answer)
        @Html.HiddenFor(Function(model) model.Answers(incr).AnswerId)
        @Html.HiddenFor(Function(model) model.Answers(incr).AnswerTemplateTag)
        @Html.HiddenFor(Function(model) model.Answers(incr).Tag)
    Next

When the view is submitted/posted, the model binder takes over before hitting the first line of code in your mvc post controller method. I then iterate through the actual formcollection and strip out the [#] using regex, because your formcollection will show your list items like this: Answers[0].Answer, Answers[0]AnswerId ,etc.:

 For x As Integer = 1 To request.Form.Count - 1
                keyname = request.Form.Keys(x)
                Debug.Write(keyname)

                val = request.Form(x).ToString()

                'If keyname contains [#] strip it. it's a list item.
                Dim pattern As String = "\[(\d+)\]"
                Dim iterpattern As String = "\d+"
                Dim rgx As New Regex(pattern)
                Dim rgxiter As New Regex(iterpattern)

                If Regex.IsMatch(keyname, pattern) Then
                    Dim match As Match = rgxiter.Match(keyname)
                    ListIteration = CInt(match.Value)
                    Dim result As String = rgx.Replace(keyname, "")
                    keyname = result
                End If

The Select Case codeblock is next. So you already know you have a strong typed class in your model, so your select can look like this:

Select Case keyname

                    Case "Answers.Answer"
                        'add code here to add to your return list. What you
                        'get in the post controller is a fully populated class.
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜