ASP.NET - отображение изображений и PDF в GridView - PullRequest
2 голосов
/ 29 ноября 2009

Я хочу отобразить в asp: GridView столбец «Изображения». Идея состоит в том, чтобы предоставить миниатюры изображения со ссылкой на изображение в реальном размере. Для некоторых строк это может быть PDF-документ. Я хотел бы, чтобы ссылка была на PDF. PDF или изображение хранятся в базе данных SQL.

Теперь у меня есть ошибка в файле обработчика (.ashx):

«Недопустимая попытка чтения при отсутствии данных.»

Это мой код:

ASP:

<asp:GridView ID="GridView1" runat="server" 
            AutoGenerateColumns="False" DataKeyNames="ID"
            DataSourceID="SqlDataSource1">
   <Columns>
      <asp:BoundField DataField="assessment_id" HeaderText="assessment_id" 
                    InsertVisible="False" ReadOnly="True"
                    SortExpression="assessment_id" />
      <asp:BoundField DataField="a_mime" HeaderText="a_mime" SortExpression="a_mime" />
      <asp:TemplateField HeaderText="a_data">       
        <ItemTemplate>
        <asp:Image ID="Image1" runat="server" ImageUrl='<%# "Handler.ashx?ID=" + Eval("ID")%>'/>
        </ItemTemplate>
      </asp:TemplateField>
  </Columns>
</asp:GridView>

<asp:SqlDataSource ID="SqlDataSource1" runat="server" 
  ConnectionString="<%$ ConnectionStrings:testConnectionString %>"
  SelectCommand="SELECT [assessment_id], [a_data], [a_mime] FROM [Assessments]">    
</asp:SqlDataSource>

Обработчик ASHX:

<%@ WebHandler Language="C#" Class="Handler" %>

public class Handler : IHttpHandler {

public void ProcessRequest (HttpContext context) 
{
    SqlConnection con = new SqlConnection();
    con.ConnectionString = ConfigurationManager.ConnectionStrings["testConnectionString"].ConnectionString;

    // Create SQL Command 
    SqlCommand cmd = new SqlCommand();
    cmd.CommandText = "Select a_data from Assessments where assessment_id =@ID";
    cmd.CommandType = System.Data.CommandType.Text;
    cmd.Connection = con;

    SqlParameter ImageID = new SqlParameter("@ID", System.Data.SqlDbType.Int);
    ImageID.Value = Convert.ToInt32(context.Request.QueryString["assessment_id"]);
    cmd.Parameters.Add(ImageID);
    con.Open();

    SqlDataReader dReader = cmd.ExecuteReader();
    dReader.Read();

    context.Response.BinaryWrite((byte[])dReader["a_data"]);

    dReader.Close();

    con.Close();
}

Если это возможно, пожалуйста, помогите мне. Если это отнимает много времени, укажите ссылку на пример или сообщение в блоге.

1 Ответ

1 голос
/ 29 ноября 2009

Причина ошибки около Invalid attempt to read when no data is present заключается в том, что DataReader не содержит никаких записей (нет изображения для данного идентификатора). Попробуйте изменить код на:

SqlDataReader dReader = cmd.ExecuteReader();

if (dReader.HasRows)
{
  while (dReader.Read())
  {
     context.Response.BinaryWrite((byte[])dReader["a_data"]);
  }

  dReader.Close();
}

Несколько предложений по улучшению

  • попытаться предсказать, когда в строке не будет изображения
  • когда вы можете обнаружить на своей странице ASP.NET, выполните вызов на страницу .ashx
  • когда вы можете обнаружить, что вам нужно отобразить ссылку на PDF, покажите хорошее статичное изображение в формате PDF, и его ссылкой будет URL.

Подумайте, по возможности, проверьте, чтобы в данной Оценке было необходимое изображение или PDF. Возможно, добавьте предложение where, чтобы как-то определить, должна ли эта запись отображать сценарий PDF или изображение.

Могу ли я также предложить вам преобразовать ваши операторы SQL в хранимую процедуру, как указано выше, и изменить ваш SqlDataSource следующим образом:

CREATE PROC ListAssessments
AS

SELECT [assessment_id]
     , [a_data]
     , [a_mime] 
     , CASE WHEN a_mime = 'PDF' THEN 1
       ELSE 0
       END AS IsPDF

FROM Assessments  

Теперь в вашем Gridview вы можете определить, хотите ли вы отобразить изображение или ссылку PDF.

<asp:TemplateField HeaderText="Image">       
  <ItemTemplate>
     <asp:PlaceHolder id="ph1" runat="server" />    
  </ItemTemplate>
</asp:TemplateField>

Настройте Gridview на событие ItemDataBound, которое вызывает новый метод, который вы можете написать.

<asp:GridView OnRowDataBound="ShowImageOrPdf" 

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

protected void ShowImageOrPdf(object sender, GridViewRowEventArgs e)
{
    const string LINK = "handler.ashx?Id={0}&Type={1}";
    GridView gv = (GridView)sender;

    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        string assessmentID = gv.DataKeys[e.Row.RowIndex].Value.ToString();
        bool isPDF =  (bool)e.Row.DataItem["IsPDF"];
        HyperLink h = new HyperLink();

        if (isPDF)
        {
            //render a link showing that it's a PDF.
            h.NavigateUrl = string.Format(LINK, assessmentID, "PDF");
            h.ImageUrl = "http://www.adobe.com/images/pdficon_large.gif";
            h.Text = "View PDF";
        }
        else
        {
            //render a thumbnail with a link to the image
            h.NavigateUrl = string.Format(LINK, assessmentID, "IMG");

            //have the handler create a thumbnail somehow.
            h.ImageUrl = string.Concat(h.NavigateUrl + "&Size=Small");
        } 
       //write the link back to the placeholder.
       e.Row.FindControl("ph1").Controls.Add(h);
    }
}

Затем в вашем .ashx вам нужно будет прочитать параметры строки запроса, чтобы определить, что выводить: изображение, эскиз или документ PDF, сохраненный в базе данных.

...