65.9K
CodeProject 正在变化。 阅读更多。
Home

ASP.NET 缩略图解决方案

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.61/5 (46投票s)

2002年9月13日

Ms-RL

12分钟阅读

viewsIcon

617877

downloadIcon

8531

一篇介绍用于生成缩略图和缩略图视图的 ASP.NET 工具集的文章。

一张截图

Test page of ThumbList control

引言

欢迎来到我在 CodeProject 的第一篇文章!上面的图片应该能让你大致了解我开发的这个代码是做什么的。在我阅读完 Framework SDK 中(非常好)的 ASP.NET 教程后,我开始了这个项目。DataList 控件给了我制作一个用户控件来以网格格式显示缩略图的想法。为了“即时”生成缩略图,我制作了一个 C# 类和一个 C# HTTP 处理程序。该解决方案的一部分(尽管是可选的)是一个 ATL COM 缩略图生成器对象。我添加了诸如分页和斜边缩略图等有用功能。在我写完第一版文章后,有些人要求在图片下方添加评论。在第二版中,我添加了评论和在线编辑功能。由于我没有 VS.NET,开发是使用免费的 Web Matrix 工具完成的。这是一个非常好的工具,有很多设计功能,不幸的是代码编辑器还不那么好。 

接下来,我将介绍如何使用缩略图工具,然后(简要地)介绍代码的重要部分。 

如何使用这些工具

我的缩略图解决方案的 ASP.NET 部分由文件 PhilipSoft.Thumbnails.ThumbGenerator.csThumbJpeg.ashx ThumbList.ascx 组成。web.config 文件包含一些应用程序设置 (appSettings),但所有这些都是可选的。下载 zip 文件并解压后,将包含它的 ThumbAspnet 文件夹设为一个虚拟目录,然后在浏览器中指向 ThumbDisplay.aspx 页面。 这是一个测试页面,其示例显示在上图中。在 Path 文本框中输入一个包含图片的 IIS 虚拟目录的路径,然后按“Regenerate thumbnails”按钮。您应该能看到该目录中图片的缩略图。尝试其他选项,并观察缩略图的变化。如果您想让“Use COM object”选项生效,则必须注册 bin 子文件夹中的 ThumbExtract.dll。 稍后将详细介绍此 COM 对象。 

ThumbJpeg.ashx 是一个基于 .NET 的 HTTP 处理程序,您可以在 <img> 标签中使用它来动态生成缩略图。缩略图不会保存在磁盘上,而是保存在缓存内存中,以便后续调用。如果您更改了某个参数,它将重新生成,而不是从缓存中获取。下面展示了该处理程序的典型用法。 

<a> 链接指向一个图像,而 <img> 标签通过其 src 属性指定一个动态生成的缩略图。 

<a href='/images/OLIMP012.jpg'>
<img src='ThumbJpeg.ashx?VFilePath=/images/OLIMP012.jpg&width=200&
height=200&Bevel=true' 
     alt='Click here'/></a> 

 HTTP 处理程序的参数以查询字符串的形式给出。它们是:

  • VFilePath:原始图像的虚拟路径。这是唯一必需的参数。如果指定的 文件不存在或不是图像,将从 NoThumb.gif 文件生成一个“无缩略图”的默认图像。 
  • Width, Height:所需的缩略图尺寸。如果未给出,则从 appSettings 读取,如果 appSettings 中未指定,则默认为 150x150。
  • AllowStretch:设置为 'true' 以允许将缩略图拉伸以适应上述尺寸。如果未给出,则默认为 false。
  • Bevel:设置为 'true' 以生成一个斜边缩略图,如上图所示。如果未给出,则默认为 false。
  • Refresh:设置为 'true' 以刷新缩略图(先清除缓存版本)。我没有使用它,它相当无用。
  • UseCOMobj:设置为 'true' 以使用 ThumbExtract.dll 中实现的 COM 对象生成缩略图(您必须先注册它)。COM 对象的 ProgID 是 'ThumbExtract.FileThumbExtract'
  • ShowComments:设置为 'true' 以在缩略图下方显示评论(如果存在)。评论保存在与图像目录相同的目录中名为 'ThumbComments.xml' 的 XML 文件中。
  • AllowEdit:如果设置为 'true',则会出现一个编辑链接,允许您编辑每个缩略图的评论。然后按“update”按钮,评论将被保存在 XML 文件中。 

使用 COM 对象(通过将 UseCOMobj 属性设置为 'true')的一个原因是,它能够生成比 C# 代码更多的文件类型的缩略图。它利用负责在您单击文件或在资源管理器中选择“缩略图”视图时生成缩略图的 shell 接口 (IExtractImage)。例如,请看下图。 该对象为 DICOM(医学)图像、HTML 文件、Powerpoint 文件和 Scribble(Visual C++ 教程)文件(绘图)生成了缩略图。我提交了另一篇文章(为您的 MFC 文档类型创建缩略图提取器对象),介绍了如何通过实现 IExtractImage 接口来开发可以为 Scribbles 和任何文件类型提取缩略图的 COM 对象。 在该文章的 zip 下载中,您可以找到 COM 组件 ThumbExtract.dll 的源代码。在本篇文章的 zip 文件中,您只能找到二进制文件。

Thumbnail using the COM object

ThumbList.ascx 基于 DataList 控件实现了一个用户控件(ThumbList),它简化了 Web 缩略图视图的创建。以下是 ThumbList 用户控件的属性

  • VPath:您想将其内容显示为缩略图的虚拟目录 
  • Filter:用于选择要显示缩略图的文件的过滤器(例如,*.jpg;*.gif)
  • Width, Height,AllowStretch,Bevel,Refresh,UseCOMobj:参见上面的说明
  • Columns:视图的列数
  • HeaderTitle:控件标题栏中出现的标题 
  • Sort:设置为 true 以按文件名排序
  • AllowPaging,PageSize:设置 AllowPaging=true 以显示包含 PageSize 个缩略图的页面
  • CurPage:设置为大于 0 的值以定义当前页。通常您不设置此值,以便用户可以通过单击控件页脚的页面链接来定义当前页。
  • HideNavBar:隐藏控件页脚中的导航栏
  • SaveThumbnails:将每个缩略图(如果尚未保存)保存到硬盘,并指向已保存的缩略图(而不是 HTTP 处理程序)。缩略图文件将保存在对应于虚拟目录的目录下的 'thumbnail' 子目录中。如果您想在繁忙的网站中使用该控件,这是一个很好的选择,因为它可以节省 CPU 时间并提高服务器的响应速度(然而,如果您让用户选择各种缩略图尺寸,那么您的硬盘上将创建许多小文件)。 此外,如果您的 Web 主机提供商不支持 ASP.NET 页面,您可以在测试服务器上运行一个 Web 爬虫程序来创建静态 HTML 页面。

如果您更改了 ThumbList.ascx 的位置(例如,将其放在子文件夹中),则必须将 ThumbJpeg.ashx 文件放在同一位置。ThumbDisplay.aspx 页面包含该控件的一个实例,并根据用户选择来操作其属性。

缩略图生成器类

此缩略图解决方案的核心是 PhilipSoft.Thumbnails.ThumbGenerator.cs 类。我将缩略图的生成封装在一个类中,因为我可以从许多 ASP.NET 页面以及 Windows Forms 页面(我尚未尝试过)调用它。创建实例后,通过调用其 SetParams(...) 函数来设置缩略图参数。然后,您可以调用 ExtractThumbnail() 函数来获取缩略图,该函数返回一个对应的 Bitmap 缩略图。GetUniqueThumbName() 函数返回一个相对于缩略图参数的唯一文件名。 下面的代码是 ExtractThumbnail() 函数的一部分,该函数使用 Bitmap 类的 GetThumbnailImage 来创建缩略图。为了保留原始图像的纵横比,我使用相同的子采样因子 f 来派生生成的 Bitmap 的实际尺寸。

// create thumbnail using .net function GetThumbnailImage

bitmapNew = new Bitmap(_path); // load original image

if(!_bStretch) { // retain aspect ratio

  widthOrig = bitmapNew.Width;
  heightOrig = bitmapNew.Height;
  fx = widthOrig/_width;
  fy = heightOrig/_height; // subsampling factors

  // must fit in thumbnail size

  f=Math.Max(fx,fy); if(f<1) f=1;
  widthTh = (int)(widthOrig/f); heightTh = (int)(heightOrig/f);
}
else {
  widthTh = _width; heightTh = _height;
}
bitmapNew = (Bitmap)bitmapNew.GetThumbnailImage(widthTh, heightTh,
  new Image.GetThumbnailImageAbort(ThumbnailCallback),IntPtr.Zero);
if(!_bBevel) return bitmapNew;
}
public bool ThumbnailCallback() { return false; }
  

如果您选择使用 COM 对象创建缩略图,将执行以下代码

 if(_oCOMThumb==null) _oCOMThumb = new FileThumbExtract();
 _oCOMThumb.SetPath(_path);
 _oCOMThumb.SetThumbnailSize(_width,_height);
 IntPtr hBitmap = (IntPtr)_oCOMThumb.ExtractThumbnail();
 bitmapNew = Bitmap.FromHbitmap(hBitmap);
 _oCOMThumb.FreeThumbnail();

FileThumbExtract 类是 COM 对象的一个包装类,使用 NET 框架工具 tlbimp.exe 生成。我不会讨论它的代码,它是基于 GotDotNet 网站上的一个示例ExtractThumbnail() 返回一个 HBITMAP 句柄(作为 long 值),该句柄在 Bitmap.FromHbitmap 静态函数中使用来创建缩略图(FromHbitmap 函数来自基类 Image,不幸的是,它在 Bitmap 类的文档中未被列出)。COM 对象的一个很棒的功能是它还可以为 URL 生成缩略图!

对生成的缩略图应用斜边效果是一个有趣的问题。在观察了 Photoshop 如何应用效果后,我意识到我应该在缩略图的边框上绘制具有递减透明度(递增 A 颜色值)的线性渐变。C# GDI+ 提供了许多功能,并且比普通的 C GDI 更容易使用,因此实现该效果并不困难。请参阅下面的代码(省略了一些行)了解实现,也许您可以使用它来创建基于参数绘制自身的 Web 或 Forms 斜边按钮。 它创建的斜边效果并不完美,但还可以接受。该效果的参数(如斜边宽度)是固定的,但您可以使其可调。 

 // ---- apply bevel

 int widTh,heTh;
 widTh = bitmapNew.Width; heTh = bitmapNew.Height;
 int BevW = 10, LowA=0, HighA=180, Dark=80, Light=255;
 // hilight color, low and high

 Color clrHi1 = Color.FromArgb(LowA,Light,Light,Light);
 Color clrHi2 = Color.FromArgb(HighA,Light,Light,Light);
 Color clrDark1 = Color.FromArgb(LowA,Dark,Dark,Dark);
 Color clrDark2 = Color.FromArgb(HighA,Dark,Dark,Dark);
 LinearGradientBrush br; Rectangle rectSide;

 Graphics newG = Graphics.FromImage(bitmapNew);
 Size szHorz = new Size(widTh,BevW);
 Size szVert = new Size(BevW,heTh);
 // ---- draw dark (shadow) sides first

 // draw bottom-side of bevel

 szHorz+=new Size(0,2); szVert+=new Size(2,0);
 rectSide = new Rectangle(new Point(0,heTh-BevW),szHorz);
 br = new LinearGradientBrush(
   rectSide,clrDark1,clrDark2,LinearGradientMode.Vertical);
 rectSide.Inflate(0,-1);
 newG.FillRectangle(br,rectSide);
 // draw right-side of bevel

 ...
 // ---- draw bright (hilight) sides next

 ...
 // draw top-side of bevel

 ...
 // draw left-side of bevel

 ...
 // dispose graphics objects and return bitmap

 br.Dispose(); newG.Dispose();
 return bitmapNew;

缩略图 HTTP 处理程序

ThumbJpeg.ashx 文件 HTTP 处理程序负责将缩略图发送到输出。在创建缩略图之前,它会检查是否已经存在具有相同参数的缩略图(已缓存)。为了启用此功能,缓存的缩略图与由 GetUniqueThumbName() 函数返回的键相关联。如果存在,它将使用该键检索它,否则它将使用 ThumbGenerator 类的服务来获取缩略图。最后,缩略图作为 JPEG 文件发送到响应。

  _oGenerator.SetParams(_path,_width,_height,_bStretch,_bBevel,_
                         bUseCOMobject);
  Cache MyCache = context.Cache;
  sCacheKey = _oGenerator.GetUniqueThumbName();
  // --- remove from cache when we want to refresh

  bool bRefresh = (context.Request["Refresh"]=="true");
  if(bRefresh) MyCache.Remove(sCacheKey);
  if(MyCache[sCacheKey] == null)
  { // the thumbnail does not exist in cache, create it...

    try {
      bitmap = _oGenerator.ExtractThumbnail();
      bFoundInCache=false;
    }
    catch(Exception e)  {
      // requested image cannot be loaded, try to load the 

      // 'NoThumb' image

      ...
    }
  }
  else bitmap = (Bitmap)MyCache[sCacheKey];
  context.Response.ContentType = "image/Jpeg";
  bitmap.Save (context.Response.OutputStream, ImageFormat.Jpeg);

如果未在应用程序缓存中找到缩略图位图,则使用 Insert 函数将其添加到其中。创建了与原始图像文件的依赖关系,因此如果原始图像发生更改,缓存的位图将变得无效并从缓存中删除。我还设置了一个滑动过期时间为 mins 分钟。无论这些设置如何,ASP.NET 缓存系统都会定期从缓存中移除对象,因此您无需担心内存使用。

 if(!bFoundInCache)  {
  CacheDependency dependency = new CacheDependency(_path);
  int mins; try {
    mins = int.Parse(ConfigurationSettings.AppSettings["SlidingExpireMinutes"]);
  } catch(ArgumentNullException ex) { mins=20; }
  MyCache.Insert(sCacheKey, bitmap ,dependency,
    Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(mins),
    CacheItemPriority.Default, new CacheItemRemovedCallback(RemovedCallback));
  dependency.Dispose();
 }
}

static public void RemovedCallback(String k, Object item, 
                                   CacheItemRemovedReason r) {
  ((Bitmap)item).Dispose();
}

ThumbList 用户控件

ThumbList.ascx 中实现的该用户控件显示缩略图视图。它基于 DataList 实例,DataList 是一个 ASP.NET 模板化数据绑定控件。数据源的创建和数据绑定在下面的 BindThumbList() 函数中实现。作为数据源,我使用了内存中创建的 DataTable dtThumbsDefaultView。该表有两个列:FilenameComment。对于要显示的虚拟目录(VPath)中的每个文件名,都会向表中添加新的一行。 XML 评论文件被加载为 DataSet(使用 ReadXml 函数)。如果它不存在,则在内存中创建它。然后,对于 XML 中的每一行,将在 dtThumbs DataTable 中搜索匹配的行来设置评论。为了支持分页,我不得不编写额外的代码来选择属于每一页的文件。不幸的是,DataList 本身不支持分页。由于 ThumbList 控件的属性可能已被调用页面更改,因此 BindThumbList() 在每次页面加载时执行,但当更新命令执行时除外。

public void BindThumbList()
      {
      String[] files; int i;
      ArrayList arFilesAll = new ArrayList();
      try {
      if(_filter.Length==0 || _filter=="*.*") {
        files = Directory.GetFiles(_path);
        arFilesAll.AddRange(files);
      }
      else { // separate different filters with ';'

        String[] filters = _filter.Split(';');
        for(i=0; i<filters.Length; i++) {
          files = Directory.GetFiles(_path,filters[i]);
          arFilesAll.AddRange(files);
        }
      }
      // create the datasource (list of files)

      for(i=0; i<arFilesAll.Count; i++)
        arFilesAll[i] = Path.GetFileName((String)arFilesAll[i]);
      MyThumbList.Attributes["TotalFiles"] = arFilesAll.Count.ToString();
      if(_bSaveThumbnails) {
        _oGenerator = new ThumbGenerator();
        String pathThumbs = _path+"\\thumbnails";
        Directory.CreateDirectory(pathThumbs);
        } // end if save thumbs

      } catch(Exception exDir) { arFilesAll = new ArrayList(); }
      // sort file-list if requested

      if(Sort)
        arFilesAll.Sort();
        
      // page thumblist if requested

      ArrayList arFilesToShow;
      if(!AllowPaging)
         arFilesToShow = arFilesAll;
      else { // create a data source with only the page files

       int totalPages = (int)Math.Ceiling((float)arFilesAll.Count/PageSize);
       if(totalPages==0) totalPages=1;
       MyThumbList.Attributes["TotalPages"] = totalPages.ToString();
       if(CurPage<1) {
         // we have not given a page from caller, get it from hidden field

         try {
          CurPage = int.Parse(hdnCurPage.Value); //Request.Form["__EVENTARGUMENT"]);

         } catch(Exception exParse) { CurPage=1; }
        }
       if(hdnPrevPath.Value!=VPath) // restart page numbering

         CurPage = 1;
       Trace.Warn("BindThumbList: Current page=" + CurPage.ToString());
       // make sure current page is in the [1,totalPages] range

       if(CurPage>totalPages) CurPage=totalPages;
       else if(CurPage<1) CurPage=1;
       // store curPage in attributes and in hidden field

       MyThumbList.Attributes["CurPage"] = CurPage.ToString();
       hdnCurPage.Value = CurPage.ToString();
       // put files of the page in the dsPageFiles array

       int startIndex = (CurPage-1)*PageSize;
       int endIndex = Math.Min(CurPage*PageSize,arFilesAll.Count);
       arFilesToShow = arFilesAll.GetRange(startIndex, endIndex-startIndex );
      } // end define page


 
       // create in-memory DataTable to be the data source

      DataTable dtThumbs = CreateCommentsTable(); //see below for this function

      DataView dvCommentsFromXML = null;
      if(ShowComments || AllowEdit) {
        DataSet dsComments = ReadCommentsFromXML();
        dvCommentsFromXML = dsComments.Tables[0].DefaultView;
      }
      // add rows with filenames

      for(i=0; i<arFilesToShow.Count; i++) {
        // Response.Write(arFilesToShow[i]);

        DataRow dr = dtThumbs.NewRow();
        dr[0] = arFilesToShow[i];
	dtThumbs.Rows.Add(dr);
      } // next file

      // add existing comments

      if((ShowComments || AllowEdit) && dvCommentsFromXML!=null) {
	for(i = 0; i < dvCommentsFromXML.Count; i++) {
	  String sFilename=((String)dvCommentsFromXML[i][0]).Trim();
           DataRow[] foundRows = dtThumbs.Select("Filename = '"+sFilename+"'");
           if(foundRows.Length>0) 
            foundRows[0][1] = dvCommentsFromXML[i][1]; // copy comment

 	}
      }
 
      MyThumbList.DataSource = dtThumbs.DefaultView;
      MyThumbList.DataBind();
} // end method

当按下 Update 按钮时,会执行 ThumbList_UpdateCommand 函数来更新包含评论的 XML 文件。通过利用 DataSet 的 XML 读写功能,我将 XML 评论文件视为关系表,因此我可以轻松地将数据源更改为传统数据库(例如 Access 文件)。我选择 XML 解决方案是因为它对于小型数据库来说很方便,而且您可以在必要时手动编辑它。您可以安全地在评论中添加 HTML 标签,因为当文件保存时,'<' 和 '>' 字符会被转义,因此 XML 结构不会被破坏。另请注意,在此缩略图控件的先前版本中,我将 DataList 的 EnableViewState 属性设置为 'false',这阻止了更新命令的执行。当将该属性设置为 'true' 时,命令正常执行。

 void ThumbList_UpdateCommand(Object sender, DataListCommandEventArgs e) 
 {
   DataRowView drvTarget; 
   String sComment = (String)((TextBox)e.Item.FindControl("txtComment")).Text;
   String sFilename = ((TextBox)e.Item.FindControl("txtFilename")).Text; 
         
   DataSet dsComments = ReadCommentsFromXML();
   DataView dvCommentsFromXML = dsComments.Tables[0].DefaultView;
   dvCommentsFromXML.RowFilter =  "Filename='"+sFilename+"'";
   // find row for filename or create a new one if does not exist

   if (dvCommentsFromXML.Count > 0) { 
      drvTarget = dvCommentsFromXML[0];
      dvCommentsFromXML.RowFilter = "";
   }
   else {
     drvTarget = dvCommentsFromXML.AddNew();
     drvTarget[0] = sFilename;
   }
   drvTarget[1] = sComment;
   drvTarget.EndEdit();
   dsComments.WriteXml(_path +"\\ThumbComments.xml");
      
   MyThumbList.EditItemIndex = -1;
   BindThumbList();
  }

  DataSet ReadCommentsFromXML() {
    DataSet dsComments = new DataSet("ThumbnailDataset");
    // read comments from XML file 

    try {
       dsComments.ReadXml(_path +"\\ThumbComments.xml");
    } catch(Exception exRead) { }
    if(dsComments.Tables.Count==0) 
      dsComments.Tables.Add(CreateCommentsTable());
    return dsComments;
   }

  DataTable CreateCommentsTable() {
   DataTable dtThumbs = new DataTable("ThumbComment");  
   DataColumn dcPrimary = new DataColumn("Filename", typeof(string));
   dtThumbs.Columns.Add(dcPrimary);
   dtThumbs.Columns.Add(new DataColumn("Comment", typeof(string)));
   dtThumbs.PrimaryKey = new DataColumn[] { dcPrimary };
   dtThumbs.CaseSensitive = false;
   return dtThumbs;
   }

项模板指定了一个链接到原始图像的缩略图。您可以看到数据绑定表达式的灵活性。ThumbUrl 是一个创建缩略图链接的函数(参数化的 HTTP 处理程序或如果 SaveThumbnails 为 true,则为已保存的缩略图)。AltString 是一个创建包含文件名和原始图像文件大小的字符串的函数。

<ItemTemplate>
  <a href="<%# String.Format("{0}/{1}",_vpath,
    ((DataRowView)Container.DataItem)["Filename"]) %>" > 
   <img border="0" 
     src="<%# ThumbUrl((String)((DataRowView)Container.DataItem)["Filename"]) %>"
     alt="<%# AltString((String)((DataRowView)Container.DataItem)["Filename"]) %>" />
  </a>
  <%# _bShowFilenames?"<br/>"+((DataRowView)Container.DataItem)["Filename"]:"" %>
  <%# ShowComments?"<br/>"+((DataRowView)Container.DataItem)["Comment"]:"" %>
  </br><asp:LinkButton id="button1" Visible='<%# AllowEdit ? true:false %>' 
      Text="Edit" CommandName="Edit" runat="server"/>
</ItemTemplate>
最棘手的部分是如何实现页面链接并响应它们。页面链接在 DataList 控件的页脚中创建,代码在 DataBound 事件的处理程序中执行。我选择该事件是因为此时已经发生了数据绑定,并且我们知道需要多少页。起初,我创建页面链接作为 LinkButton 控件,并定义了一个通用的命令处理程序。在处理程序中,页码是从 CommandEventArgs 中确定的。然而,我不得不重新进行数据绑定才能显示用户选择的页面。我发现了一个更好的解决方案,通过利用 Page 类的 RegisterClientScriptBlock 函数来避免双重数据绑定。在页面加载时,会添加一个 GoToPage 客户端 javascript 函数(请参阅下面的代码)。这个函数由页面链接执行。它将 hdnCurPage 隐藏字段的值设置为参数 n(页码)。ClientID 属性允许从客户端访问服务器控件!在回发后,我们可以在页面加载时从隐藏字段中检索页码(另请参阅上面的 BindThumbList() 函数)。Page 类的 GetPostBackEventReference 函数返回对回发函数的引用,该函数会重新提交表单。这一点很重要,因为如果您创建一个指向同一页面的简单链接而表单未重新提交,则服务器控件会丢失其状态。
void Page_Load(Object Src, EventArgs e)
{
// register client script to go to a next page

StringBuilder scriptb = new StringBuilder();
scriptb.Append("<script
language="\""javascript\">\n");
scriptb.Append("//<!--\n function GoToPage(vpath,n) { \n");
scriptb.AppendFormat("document._ctl0.{0}.value=n; \n",hdnCurPage.ClientID);
scriptb.Append(Page.GetPostBackEventReference(this));
scriptb.Append("\n } \n//-->\n </");
scriptb.Append("script>");
 
if(!Page.IsClientScriptBlockRegistered("clientGotoPageScript"))
  Page.RegisterClientScriptBlock("clientGotoPageScript",scriptb.ToString());
 
// if not in update, bind every time since parameters may have change

if(MyThumbList.EditItemIndex < 0)
   BindThumbList();
}

以下代码片段显示了如何创建“Next >>”导航按钮。plLinks 是 DataList 页脚中的一个 PlaceHolder 服务器控件。包含 VPath 在链接中是为了让链接的颜色(访问过的颜色或未访问的颜色)取决于页码和虚拟目录。其他页面导航链接以类似的方式创建。

  plLinks.Controls.Add(new LiteralControl(String.Format(
    "  <A href=\"javascript:GoToPage('{0}',{1});\">Next >></A>",VPath,CurPage+1)));

结论

我希望您觉得我的缩略图解决方案很有用并加以使用。我不是专业的 Web 开发人员,也无法在网站上进行测试,但是,我使用它来查看 CD 上的缩略图!(我的系统安装了 Win2000 Pro 和 PWS)。 我喜欢编写代码,实际上这是我的第一个 C# 代码。ASP.NET 模型简化了 Web 编程,使其类似于桌面编程。最后,我建议任何有兴趣的人将 ThumbList 控件重写为一个自定义(渲染)控件,因为根据文档,渲染比组合更快。 可以使用 Page 类的 RegisterHiddenField 方法以编程方式发出隐藏字段。您也可以从 DataList 控件派生用户控件并覆盖一些函数... 我猜 :)

© . All rights reserved.