开发者

Get images by foreign key

I had table had data about product photos and this table had a relation to product table and product may be has more than Image. I did my code well开发者_如何学Go to get all images for product by productID query string but only first image retrieved. Note that ProductID in handler page is a foreign key into the Photobank images table, also I note that productID had value of ID table didnot the productID:

stored proc:

ALTER proc [dbo].[SP_GetPhotoBank]
(
@ProductID Int 
)
as
SELECT     ID, ProductID, DesignImage
FROM       ProductImages
where      ProductID=@ProductID

Markup:

<div>
    <asp:DataList ID="DLProduct" runat="server" OnItemDataBound="DLProduct_ItemDataBound">
        <ItemTemplate>
            <table style="width: 100%;">
                <tr>
                    <td>
                        <asp:Label ID="LblModel" runat="server" Text='<%#Eval("Model") %>' Style="color: #CC3300"></asp:Label>
                    </td>
                    <td>
                        &nbsp;
                    </td>
                </tr>
                <tr>
                    <td colspan="2">
                                                </td>
                </tr>
                <tr>
                    <td>
                        <asp:Image ID="IMGPhotoBank" runat="server" ImageUrl='<%#Eval("ProductID","~/Handlers/PhotoBankByProductID.ashx?ProductID={0}") %>' />
                    </td>
                   </tr>
               </table>
           </ItemTemplate>
       </asp:DataList>
   </div>

Code:

public void ProcessRequest(HttpContext context)
{
    using (SqlConnection con = Connection.GetConnection())
    {           
        SqlCommand com = new SqlCommand("SP_GetPhotoBank", con);
        com.CommandType = System.Data.CommandType.StoredProcedure;
        com.Parameters.Add(Parameter.NewInt("@ProductID", context.Request.QueryString["ProductID"].ToString()));
        SqlDataReader dr = com.ExecuteReader();
        if (dr.Read() && dr != null)
        {
            Byte[] bytes2 = (Byte[])dr["DesignImage"];
            context.Response.BinaryWrite(bytes2);
            dr.Close();
        }
    }
}


I think that you need to loop through the data in your data reader because currently you will only ever read the first result, then close the data reader.

while(dr.Read())
{
    // add results to some collection
}

// close the reader and tidy up
dr.Close();
dr.Dispose();

// now render your data 


You cannot send multiple images to the browser in a single request. Basically you have two options:

  1. Iterate over the images in your page
  2. Merge all images into a single file like Shadow Wizard suggested

In most cases option 1 will do. What you need to do is:

  • Make sure each image can be accessed through a unique key. Your handler should return 1 image per request. So your URL would look similar to this: ~/Handlers/PhotoBank.ashx?ImageID={0}
  • List the images for each product so you can access them during databinding. I can't really make out how that would look in your application. You could wrap the image tag in a repeater to iterate over the image list.


You need to merge all the images from database into one Bitmap then send this merged bitmap to the browser.

Basically the steps are:

First, store the byte[] of the images data in List while looping over the data reader.

Second step: Iterate over the above List and for each byte[] build bitmap using such code:

MemoryStream stream = new MemoryStream(currentData);
Bitmap bitmap = new Bitmap(stream);

Calculate the sum of the Height of each bitmap and the maximum Width, and built new Bitmap object with that Height and Width to hold the merged images:

Bitmap mergedImages = new Bitmap(maxWidth, totalHeight);

Third step: Add the images you buillt above (the Bitmap built from each byte[]) to mergedImages using such code:

int yPos = 0;  
using (Graphics g = Graphics.FromImage(mergedImages))  
{  
   foreach (Bitmap curBitmap in arrBitmaps)  
    {  
        g.DrawImage(curBitmap, 0, yPos);  
        yPos += curBitmap.Height;  
    }  
}

Then final step is send the merged bitmap to browser:

using (MemoryStream stream = new MemoryStream())
{
   bitmap.Save(stream, ImageFormat.Jpeg);
   Response.BinaryWrite(stream.GetBuffer());
}

I know it might look complicated but I believe that doing it step by step you'll eventually get the idea.


Theres a lot of your code missing. But I'll try to map this out as nicely as possible.

1) your data list must be producing a list of objects. Verify this by pulling up the page and seeing a list of products. They probably have a bunch of broken images.

2) view the source html of the output page. You'll see some URLs of your broken product images. Does the URL look correct? It's probably something like /myproductimage.ashx?pid=5554172.

3) after you get the URLs generated correctly, ignore the product page. From now in, you're testing the image handler. It's best to think about it this way because it has, in fact, nothing to do with your DataGrid.

4) Put that product image handler URL into your browser's bar and see what comes up. Probably nothing. But if it's an HTTP 404 then you know that your handler isn't wired correctly. I like using .ashx handlers for this kind of task. It's more appropriate and a full aspx page.

5) lastly, after you get the handler being called correctly. Set the Response.ContentType to 'image/jpeg' or 'image/png' depending on what was stored in your database. I suggest adding this as a column next to the image data so you know what format the data is in.

If this isn't clear enough, hit me up and I can maybe post an old product image handler code here for you as an example.


The problem occurs because you are trying to process several images in the same request to the handler, instead make sure to expose URLs which return single images each (each request to the handler should return one image only).

In other words, you have now handler which exposes the entry point like this:

~/Handlers/PhotoBankByProductID.ashx?ProductID={0}

But, instead, you should think of reconstructing the handler, so that it exposes the entry point URL like this:

~/Handlers/PhotoBankByProductID.ashx?ProductID={0}&ID={1}

where {1} is the ID of a record from ProductImages table.

Make sure this URL returns the image retrieved by ProductID and ID both at the same time.

Then, in your DataList, make sure to use this kind of new URL. For this, retrieve the ID-s of the images for each displayed product in each ItemTemplate and then have another nested list-like control, which displays Image elements for each product image ID for the current ProductID.

Though this seems a little overhead to retrieve image ID-s for each ItemTemplate. In such case, if you are ambitious enough, you can retrieve all needed products first, then retrieve all the images associated to each product (in one result-set all), then bind to the products list, and then, for each nested list of product images, find corresponding images from the same result-set.

For making the inner list bind, you will need OnItemDataBound event handler, which I see you already have as a good starting point.

I hope this helps!

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜