如何将IEnumerable序列绑定到具有多个列的容器?

MrG*_*rki 1 asp.net-mvc ienumerable foreach-loop-container razor asp.net-mvc-3

我相信我找不到合适的标题来解释我的问题,但我认为这是最好的简短解释.

请让我解释一下细节.

我想在页面上显示我的图片列表,并@foreach在MVC 3上使用循环.

部分查看此列表如下:

@model IEnumerable<Picture>
@foreach (var item in Model)
{
    <a href="@item.PicId">
        <img height="35px" style="padding-top:3px" src="ImageHandler.ashx?id=@item.PicId" id="pictureMy" />
    </a>
}
Run Code Online (Sandbox Code Playgroud)

您可能已经了解我正在向此部分视图发送一个列表,它将图片放在一列上.

它没有任何问题,但我希望每行显示3张图片,但无法管理.

任何指导将非常感谢.

在此先感谢您的帮助.

Dar*_*rov 6

您可以将它们分组为3:

@model IEnumerable<Picture>
@foreach (var item in Model.Select((value, index) => new { value, index }).GroupBy(x => x.index / 3))
{
    <div>
    @foreach (var picture in item)
    {
        <a href="@picture.value.PicId">
            <img height="35px" style="padding-top:3px" src="ImageHandler.ashx?id=@picture.value.PicId" id="pictureMy" />
        </a>
    }
    </div>
}
Run Code Online (Sandbox Code Playgroud)

但老实说,这种分组并不是应该在视图中完成的.您应该定义视图模型,然后让控制器操作执行分组并返回视图模型.

那么让我们从定义我们的视图模型开始:

public class PictureViewModel
{
    public int PicId { get; set; }
}

public class GroupedPicturesViewModel
{
    public IEnumerable<PictureViewModel> Pictures { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

那么控制器动作:

public ActionResult Index()
{
    // fetch the pictures from the DAL or something
    IEnumerable<Picture> pictures = ... 

    // Now build the view model
    var model = pictures
        .Select((value, index) => new { value, index })
        .GroupBy(x => x.index / 3)
        .Select(x => new GroupedPicturesViewModel
        {
            Pictures = x.Select(p => new PictureViewModel
            {
                PicId = p.value.PicId
            })
        }
    );
    return View(model);
}
Run Code Online (Sandbox Code Playgroud)

那么相应的观点:

@model IEnumerable<GroupedPicturesViewModel>
@Html.DisplayForModel()
Run Code Online (Sandbox Code Playgroud)

然后是GroupedPicturesViewModeltype(~/Views/Shared/DisplayTemplates/GroupedPicturesViewModel.cshtml)的相应显示模板:

@model GroupedPicturesViewModel
<div>
    @Html.DisplayFor(x => x.Pictures)
</div>
Run Code Online (Sandbox Code Playgroud)

最后是PictureViewModeltype(~/Views/Shared/DisplayTemplates/PictureViewModel.cshtml)的显示模板:

@model PictureViewModel
<a href="@Model.PicId">
    <img class="image" src="@Url.Content("~/ImageHandler.ashx?id=" + Model.PicId)" alt="" />
</a>
Run Code Online (Sandbox Code Playgroud)

最让我烦恼的是这个锚.看起来很难看.你不觉得吗?看起来像意大利面条代码.

让我们通过编写一个自定义的,可重用的HTML帮助器来改进它,它将渲染这些图片:

public static class HtmlExtensions
{
    public static IHtmlString Picture(this HtmlHelper<PictureViewModel> htmlHelper)
    {
        var anchor = new TagBuilder("a");
        var picture = htmlHelper.ViewData.Model;
        var id = picture.PicId.ToString();
        var urlHelper = new UrlHelper(htmlHelper.ViewContext.RequestContext);

        // You probably need another property on your view model here as this 
        // id is suspicious about href but since that's what you had in your 
        // original code I don't know what is your intent.
        anchor.Attributes["href"] = id;
        var image = new TagBuilder("img");
        image.Attributes["alt"] = "";
        image.Attributes["src"] = urlHelper.Content(
            "~/ImageHandler.ashx?id=" + urlHelper.Encode(id)
        );
        image.AddCssClass("image");
        anchor.InnerHtml = image.ToString();
        return new HtmlString(anchor.ToString());
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在显示模板中我们将简单地:

@model PictureViewModel
@Html.Picture()
Run Code Online (Sandbox Code Playgroud)

这就是它.无需编写循环.一切都按惯例运作.