Можно ли использовать форму для отправки списка в MVC? - PullRequest
0 голосов
/ 13 марта 2012

Я бы хотел, чтобы пользователи сайта загружали несколько изображений одновременно, максимум до 5. Я создал все свои ViewModels, а также метод [HttpPost], который будет обрабатывать список изображений и выполнять итерации.через каждого, сохраняя их.

Мой вопрос: как мне получить этот список в методе Post?

У меня есть следующий код для моих ViewModels:

public class ImageCreateViewModel
{
    public int ImageId { get; set; }

    public int CollectionId { get; set; }

    [Required(ErrorMessage = "Please enter a description of the photo.")]
    [MaxLength(50)]
    public string Description { get; set; }

    [Required(ErrorMessage = "Please attach an image.")]
    public HttpPostedFileBase Image { get; set; }

    public string Location { get; set; }

    public int Order { get; set; }
}

public class ImagesCreateViewModel : ImageCreateViewModel
{
    public List<ImageCreateViewModel> Images { get; set; }

    public MyEnumerator GetEnumerator()
    {
        return new MyEnumerator(this);
    }
}


public class MyEnumerator
{
    int index;
    ImagesCreateViewModel imagesCreateViewModel;

    public MyEnumerator(ImagesCreateViewModel imagesCreateViewModel)
    {
        this.imagesCreateViewModel = imagesCreateViewModel;
        index = -1;
    }

    public bool MoveNext()
    {
        index++;
        return (index < imagesCreateViewModel.Images.Count());
    }

    public ImageCreateViewModel Current
    {
        get
        {
            return (imagesCreateViewModel.Images[index]);
        }
    }
}

А вот мой Контроллер:

[HttpPost]
public ActionResult CreateImages(ImagesCreateViewModel imagesEditViewModel)
{
    if (!ModelState.IsValid)
    {
        return View(imagesEditViewModel);
    }

    foreach (ImageCreateViewModel imageCreateViewModel in imagesEditViewModel)
    {
        string fileName = Guid.NewGuid().ToString();
        string serverPath = Server.MapPath("~");
        string contentPath = String.Format("Content\\{0}\\Content\\Images\\{1}", Helper.Helper.ResolveBrand(), fileName);
        string imagePath = serverPath + contentPath;

        bool success = Helper.Helper.SaveImage(imagePath, imageCreateViewModel.Image.InputStream);

        if (success)
        {
            Image image = new Image
            {
                Collection = ds.Single<Collection>(c => c.CollectionId == imageCreateViewModel.CollectionId),
                Description = imageCreateViewModel.Description,
                Location = contentPath,
                Order = Helper.Helper.GetImageOrder(imageCreateViewModel.CollectionId)
            };

            ds.InsertOnSubmit<Image>(image);
            ds.SubmitChanges();
        }

        else
            //TODO: Write Error to them
            success = false;
    }

    return RedirectToAction("Collection");

}

Но когда я генерирую View для этого метода, он имеет возможность манипулировать только одним изображением за раз (который я должен редактировать, чтобы позволить им загружать изображение):

@using (Html.BeginForm(null, null, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>New Image</legend>

        <div class="editor-label">
            @Html.LabelFor(model => model.Description)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Description)
            @Html.ValidationMessageFor(model => model.Description)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Image)
        </div>
        <div class="editor-field">
            @Html.ValidationMessageFor(model => model.Image)
            <input type="file" name="Image" />
        </div>

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

Ответы [ 5 ]

3 голосов
/ 13 марта 2012

Вот код, который я использовал на своем сайте для загрузки нескольких изображений:


ОК, это простой пример того, как это сделать. Конечный результат:

enter image description here

HTML-разметка представляет собой простую форму с кнопкой отправки.

@using (Html.BeginForm("Create", "Product", FormMethod.Post, new { enctype = "multipart/form-data" })) {
    @Html.ValidationSummary()

    <div class="form-field">
        <p>Select pictures:</p>
        <div class="upload-container">
            <div class="upload">
                <input type="file" name="files" id="file1" /> 
                <img src="@Url.Content("~/Public/images/delete.png")" alt="Remove picture." />
            </div>
        </div>        
    </div>

    <div class="form-field">
        <input type="submit" value="Create" />
    </div>
}

Нам также нужно немного магии jQuery, чтобы каждый раз, когда кто-то добавляет изображение, мы позволяли ему также добавлять больше по мере необходимости. Пользователь может загрузить N изображений. Мы используем метод on(), чтобы события связывались с каждым вновь созданным элементом.

Обратите внимание, что имена добавленных входных данных - это «файлы», то же имя, которое мы используем в ActionMethod.

<script type="text/javascript">
    $(document).ready(function () {
        var currentImage = 1;
        $("body").on("change", "input[name='files']", function () {
            var pathToRemoveIcon = "@Url.Content("~/Public/images/delete.png")";
            currentImage = currentImage + 1;
            var htmlToAppend = '<div class="upload"><input type="file" name="files" id="file' + currentImage + '" /><img src="' + pathToRemoveIcon + '" alt="Remove picture." /></div>';
            $('.upload-container').append(htmlToAppend);
        }).on("click", ".upload img", function () {
            if ($(this).parent().siblings().length > 0) {
                $(this).parent().remove();    
            }
        });
    });
</script>

И, наконец, код контроллера, который мы получаем, модель, которую мы хотим связать, а также множество файлов:

[HttpPost]
public ActionResult Create(ProductModel model, IEnumerable<HttpPostedFileBase> files)
{
    try
    {
        if (ModelState.IsValid)
        {
            foreach (var file in files)
            {
                // Verify that the user selected a file
                if (file != null && file.ContentLength > 0)
                {
                    // extract only the filename
                    var fileName = Path.GetFileName(file.FileName);

                    // etc.
                }
            }
        }
        return RedirectToAction("Index");
    }
    catch
    {
        return View(model);
    }
}
2 голосов
/ 13 марта 2012

Возможно, но у вас будет больше работы, чем просто автоматическое создание представления.Ниже приведено сообщение в блоге Фила Хаака, в котором подробно рассказывается, как создавать представления HTML, удобные для ModelBinding в MVC и коллекциях.

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

Еще одно сообщение Скотта Ханслемана на эту тему.http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx

1 голос
/ 13 марта 2012

Я не уверен, что это перейдет к генерации модели должным образом, но если вы можете использовать HTML5, то вы можете использовать атрибут input multiple для разрешения более одного ввода. Признаться, это не очень красиво в хроме, хотя

Вот документация

И вот хороший пример, который делает вещи немного красивее

0 голосов
/ 13 марта 2012

Вы можете загрузить несколько файлов одним постом.

Просто задайте имя файла для загрузки с другим именем для каждого из них, и в вашем контроллере выполните foreach в Request.Files.Нечто похожее на это:

foreach (var file in Request.Files)
{
  if (file.ContentLength > 0)
  ... do something ...

}

Вот образец

0 голосов
/ 13 марта 2012

MVC позволит вам принять несколько загрузок файлов в действии, приняв список HttpPostedFileBase объектов. Вам необходимо убедиться, что все элементы управления загрузкой файлов имеют то же имя, что и аргумент метода действия.

public ActionResult UploadFiles(IEnumerable<HttpPostedFileBase> files)
{
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...