Binding arrays with missing elements in asp.net mv

2020-02-04 05:47发布

I am trying to bind a dynamic array of elements to a view model where there might be missing indexes in the html

e.g. with the view model

class FooViewModel
{
   public List<BarViewModel> Bars { get; set; }
}

class BarViewModel
{
   public string Something { get; set; }
}

and the html

<input type="text" name="Bars[1].Something" value="a" />
<input type="text" name="Bars[3].Something" value="b" />
<input type="text" name="Bars[6].Something" value="c" />

at the moment, bars will just be null. how could I get the model binder to ignore any missing elements? i.e. the above would bind to:

FooViewModel
{
     Bars
     {
            BarViewModel { Something = "a" },
            BarViewModel { Something = "b" },
            BarViewModel { Something = "c" }
     }
}

4条回答
Lonely孤独者°
2楼-- · 2020-02-04 06:02

A possible workaround could be to instantiate the ViewModel and the collection to the correct size (assuming it's known), then update it with TryUpdateModel... something like:

    [HttpPost]
    public ActionResult SomePostBack(FormCollection form)
    {
        // you could either look in the formcollection to get this, or retrieve it from the users' settings etc.
        int collectionSize = 6; 

        FooViewModel bars = new FooViewModel();
        bars.Bars = new List<BarViewModel>(collectionSize);
        TryUpdateModel(bars, form.ToValueProvider());

        return View(bars);
    }H
查看更多
虎瘦雄心在
3楼-- · 2020-02-04 06:05

MVC is able to populate list itself.

public ActionResult Index(FooViewModel model)
{
   ...

So no matter if anything is missing mvc will create new List<BarViewModel> and for each found index - [1],[3],[6] it will create new BarViewModel and add it to List. So you will get FooViewModel with populated Bars.

查看更多
叼着烟拽天下
4楼-- · 2020-02-04 06:12

i didnt know even that worked!

bearing that in mind, id have done something like:

<input type="text" name="Bars.Something" value="a" />
<input type="hidden" name="Bars.Something" value="" />
<input type="text" name="Bars.Something" value="b" />
<input type="hidden" name="Bars.Something" value="" />
<input type="hidden" name="Bars.Something" value="" />
<input type="text" name="Bars.Something" value="c" />

which would hopefully post

a,,b,,,c

but I suspect that will bind in the same way as you describe

Youre probably going to have write a custom model binder that looks for the max index, makes a list of that size then puts the elements in the correct place.

Saying all that, wait for someone else to post a really simple attribute you can put on your property that makes it just work ;D

查看更多
Animai°情兽
5楼-- · 2020-02-04 06:25

Add the .Index as your first hidden input to deal with out of sequence elements as explained in this Phil Haacked blog post:

<input type="text" name="Bars.Index" value="" />
<input type="text" name="Bars[1].Something" value="a" />
<input type="text" name="Bars[3].Something" value="b" />
<input type="text" name="Bars[6].Something" value="c" />
查看更多
登录 后发表回答