foreach循环为mvc视图中的所有帖子显示相同的图像

时间:2015-04-26 12:48:33

标签: c# asp.net asp.net-mvc linq entity-framework

我似乎无法在我的应用程序中显示每个帖子的单独图片。所有图像都与列表中的最后一个图像相同。我需要将每个Pictures的{​​{1}}转换为base64。在控制器中,我试图抓取每个帖子对象并将Picture属性转换为base64,然后将其添加到post,但是ViewBag.ImageToShow只能容纳一个项目,所以我的所有图像都设置为最后一个图像我的ImageToShow列表。如果我为posts创建list<string>作为下面提到的答案之一,我就不知道如何正确索引它们。

型号:

ViewBag

控制器:

    public partial class Post
    {
        public Post()
        {
            this.Tags = new HashSet<Tag>();
        }

        public int Id { get; set; }
        public string BlogUserEmail { get; set; }
        public int CategoryId { get; set; }
        public string Title { get; set; }
        public string ShortDescription { get; set; }
        public string Description { get; set; }
        public string Meta { get; set; }
        public string UrlSlug { get; set; }
        public bool Published { get; set; }
        public System.DateTime PostedOn { get; set; }
        public Nullable<System.DateTime> Modified { get; set; }
        public byte[] Picture { get; set; }

        public virtual BlogUser BlogUser { get; set; }
        public virtual Category Category { get; set; }
        public virtual ICollection<Tag> Tags { get; set; }
    }
}

查看:

    public ActionResult Index()
    {
        var posts = db.Posts.Where(p => p.BlogUserEmail == User.Identity.Name).Include(p => p.BlogUser).Include(p => p.Category);
        foreach (var item in posts) // this is wrong 
        {
            byte[] buffer = item.Picture;
            ViewBag.ImageToShow = Convert.ToBase64String(buffer);
        }
        return View(posts.ToList());
    }

请注意,在我创建动态布局时,我将@for (int i = 0; i < Model.Count(); i += 3) { <div class="row"> @foreach (var item in Model.Skip(i).Take(3)) { <div class="col-md-4 portfolio-item"> <a href="@Url.Action("Details", "Post", new { urlslug = item.UrlSlug })"> <img class="img-responsive" src="@Html.Raw("data:image/jpeg;base64," + ViewBag.ImageToShow)" alt=""> </a> <h3> <a href="@Url.Action("Details", "Post", new { urlslug = item.UrlSlug })">@Html.DisplayFor(modelItem => item.Title)</a> </h3> <p>@Html.DisplayFor(modelItem => item.ShortDescription)</p> @Html.ActionLink("Edit", "Edit", new { id = item.Id }) | @Html.ActionLink("Details", "Details", new { urlslug = item.UrlSlug }) | @Html.ActionLink("Delete", "Delete", new { id = item.Id }) </div> } </div> } 放在foreach循环中。对于帖子列表中的每个图像显示图像。但是我无法将viewbag作为列表存储并返回与视图foreach相关的正确图像,同时必须将图像转换为base64。

4 个答案:

答案 0 :(得分:3)

您的代码问题在于控制器中Index函数的循环。你在循环中设置ViewBag.ImageToShow,这个变量只能容纳一个对象,因此通过在循环中设置它不断重置。

这里有两个选项:

使用ViewBag

在您的控制器中,创建一个分别包含int, string,ID和值的词典。在循环内部,您需要为找到的每个图像添加一个条目。

    public ActionResult Index()
    {
        Dictionary<int, string> postImages = new Dictionary<int, string>();
        var posts = db.Posts.Where(p => p.BlogUserEmail == User.Identity.Name).Include(p => p.BlogUser).Include(p => p.Category);
        foreach (var item in posts) 
        {
            byte[] buffer = item.Picture;
            postImages.Add(item.ID, Convert.ToBase64String(buffer));
        }
        ViewBag.Images = postImages;
        return View(posts.ToList());
    }

在你的视图中,你应该在开始循环之前声明一个包含列表的局部变量:

var images = (Dictionary<int, string>)ViewBag.Images;

现在,在循环中,您可以从列表中获得所需的图像:

images.Single(i => i.Key == item.ID).Value;

按要求提供完整示例:

@{Dictionary<int, string> images = (Dictionary<int, string>)ViewBag.Images;
@for (int i = 0; i < Model.Count(); i += 3)
{
    <div class="row">
        @foreach (var item in Model.Skip(i).Take(3))
        {
            <div class="col-md-4 portfolio-item">
                <a href="@Url.Action("Details", "Post", new { urlslug = item.UrlSlug })">
                    <img class="img-responsive" src="@Html.Raw("data:image/jpeg;base64," + images.Single(image => image.Key == item.ID).Value)" alt="">
                </a>
                <h3>
                    <a href="@Url.Action("Details", "Post", new { urlslug = item.UrlSlug })">@Html.DisplayFor(modelItem => item.Title)</a>
                </h3>

                <p>@Html.DisplayFor(modelItem => item.ShortDescription)</p>
                @Html.ActionLink("Edit", "Edit", new { id = item.Id }) |
                @Html.ActionLink("Details", "Details", new { urlslug = item.UrlSlug }) |
                @Html.ActionLink("Delete", "Delete", new { id = item.Id })
            </div>
        }
    </div>
  }
}

使用第二个模型

我个人以前从未使用过这个,但我已经看过它,我想我只是提到它。

要使用此技术,您必须创建第二个模型,此模型将保留原始模型和图像。

public class PostImageModel
{
    public Post Post { get; set; }
    public string Image { get; set; }
}

现在在控制器内部,我们必须创建一个新创建的模型列表,并用所需的数据填充它:

    public ActionResult Index()
    {
        List<PostImageModel> postsWithImages = new List<PostImageModel>();
        var posts = db.Posts.Where(p => p.BlogUserEmail == User.Identity.Name).Include(p => p.BlogUser).Include(p => p.Category);
        foreach (var item in posts) 
        {
            item.Picture = null;
            postsWithImages.Add(new PostImageModel()
            {
                Post = item,
                Image = Convert.ToBase64String(item.Picture)
            });
        }
        return View(postsWithImages);
    }

编辑:添加,以便代码在完成转换后清空字节数组。 (谢谢@Serv)。

您的循环将保持不变,除了使用item.Title之外,您现在应该使用item.Post.Title

请注意,您现在应该在视图顶部添加@model ExampleNamespace.Models.PostImageModel以使用此模型。

答案 1 :(得分:2)

您正在将每张图片分配给相同的ViewBag属性,这是正常的,您始终可以看到相同的图片。

您应该向模型添加一个名为ImageToShow的新字符串属性,标记为NotMapped属性:

public partial class Post
{
    public Post()
    {
        this.Tags = new HashSet<Tag>();
    }

    public int Id { get; set; }
    public string BlogUserEmail { get; set; }
    public int CategoryId { get; set; }
    public string Title { get; set; }
    public string ShortDescription { get; set; }
    public string Description { get; set; }
    public string Meta { get; set; }
    public string UrlSlug { get; set; }
    public bool Published { get; set; }
    public System.DateTime PostedOn { get; set; }
    public Nullable<System.DateTime> Modified { get; set; }
    public byte[] Picture { get; set; }

    [NotMapped]
    public string ImageToShow { get; set; }

    public virtual BlogUser BlogUser { get; set; }
    public virtual Category Category { get; set; }
    public virtual ICollection<Tag> Tags { get; set; }
}

控制器:

    public ActionResult Index()
    {
        var posts = new List<MvcApplication2.Models.Post>();
        foreach (var item in posts) // this is wrong 
        {
            byte[] buffer = item.Picture;
            item.ImageToShow = Convert.ToBase64String(buffer);
        }
        return View(posts.ToList());
    }

查看:

@for (int i = 0; i < Model.Count(); i += 3)
{
    <div class="row">
        @foreach (var item in Model.Skip(i).Take(3))
        {
            <div class="col-md-4 portfolio-item">
                <a href="@Url.Action("Details", "Post", new { urlslug = item.UrlSlug })">
                    <img class="img-responsive" src="@Html.Raw("data:image/jpeg;base64," + item.ImageToShow)" alt="">
                </a>
            <h3>
                <a href="@Url.Action("Details", "Post", new { urlslug = item.UrlSlug })">@Html.DisplayFor(modelItem => item.Title)</a>
            </h3>

            <p>@Html.DisplayFor(modelItem => item.ShortDescription)</p>
            @Html.ActionLink("Edit", "Edit", new { id = item.Id }) |
            @Html.ActionLink("Details", "Details", new { urlslug = item.UrlSlug }) |
            @Html.ActionLink("Delete", "Delete", new { id = item.Id })
        </div>
        }
    </div>
}    

答案 2 :(得分:1)

有几种方法可以做到这一点。第一个也是最快的是将所有图像放在一个集合中,然后将该集合存储在ViewBag中。现在,你只存储一个图像 - 最后一个。

public ActionResult Index()
{
    var posts = db.Posts.Where(p => p.BlogUserEmail == User.Identity.Name).Include(p => p.BlogUser).Include(p => p.Category);

    // create collection
    List<string> ImageCollection = new List<string>();
    foreach (var item in posts)
    {
        //add images to list
        ImmageCollection.Add(Convert.ToBase64String(item.Picture));
    }
    //Add list to ViewBag
    ViewBag.ImageToShow = ImageCollection;
    return View(posts.ToList());
}

现在您可以使用迭代器在视图中访问它:

<img class="img-responsive" src="@Html.Raw("data:image/jpeg;base64," + ViewBag.ImageToShow[i])" alt="">

就个人而言,我为此创建了一个ViewModel,因为您不会使用Post类的所有属性。

创建一个包装所需属性的类。让我们称之为PortfolioVM:

public class PortfolioVM
{
    public int Id { get; set; }
    public string UrlSlug { get; set; }
    //not Byte[]!
    public string Picture { get; set; }
    public string ShortDescription { get; set; }
}

现在在你的控制器中我们将使用ViewModel:

public ActionResult Index()
{
    var posts = db.Posts.Where(p => p.BlogUserEmail == User.Identity.Name)
                        .Include(p => p.BlogUser)
                        .Include(p => p.Category)
                        .Select(vm => new PortfolioVM(){
                            Id = vm.Id,
                            UrlSlug = vm.UrlSlug,
                            Picture = Convert.ToBase64String(vm.Picture),
                            ShortDescription = vm.ShortDescprition
                         }) ;

    return View(posts);
}

现在我们需要更改您的视图,以使用新的ViewModel。将声明模型的第一行更改为:

//insert correct namespace!
@model IEnumerable<Namespace.Subfolder.PortfolioVM)

在此之后,您可以像查看视图的其他所有属性一样显示图像:

    @foreach (var item in Model.Skip(i).Take(3))
    {
        <div class="col-md-4 portfolio-item">
            <a href="@Url.Action("Details", "Post", new { urlslug = item.UrlSlug })">
                <img class="img-responsive" src="@Html.Raw("data:image/jpeg;base64," + item.Picture)" alt="">
            </a>
            <h3>
                <a href="@Url.Action("Details", "Post", new { urlslug = item.UrlSlug })">@Html.DisplayFor(modelItem => item.Title)</a>
            </h3>

            <p>@Html.DisplayFor(modelItem => item.ShortDescription)</p>
            @Html.ActionLink("Edit", "Edit", new { id = item.Id }) |
            @Html.ActionLink("Details", "Details", new { urlslug = item.UrlSlug }) |
            @Html.ActionLink("Delete", "Delete", new { id = item.Id })
        </div>
    }

答案 3 :(得分:-3)

你做错了!将所有图像存储在同一个变量中!

public ActionResult Index()
{
    var posts = db.Posts.Where(p => p.BlogUserEmail == User.Identity.Name).Include(p => p.BlogUser).Include(p => p.Category);

        // this is what you should do, or something like this
        ViewBag.ImagesToShow = new List<String>();

    foreach (var item in posts)
    {
        byte[] buffer = item.Picture;

        // this is really wrong!
        //ViewBag.ImageToShow = Convert.ToBase64String(buffer);

        ViewBag.ImagesToShow.Add(Convert.ToBase64String(buffer));
    }
    return View(posts.ToList());
}

您还需要更改视图