可以重用进度栏服务器控件

分享于 

19分钟阅读

Web开发

  繁體

Sample Image

介绍

本文描述了创建可以重用进度条的过程,可以在服务器端或者客户端控制它。

背景

在 web UI开发中,有时需要显示资源使用情况信息。 进度条的一些应用程序包括显示队列中的消息量,或者显示用户最大用户数目。 我第一次尝试创建基于HTML的进度栏时,我使用了 span 在 ASP.NET 服务器页中可视地表示进度栏的元素。 然后我用了一个 iframe 在要显示进度栏的位置嵌入该服务器页。 这种方法从非常复杂 span 为了正确显示进度栏和从包含页面中进行样式交互,嵌套。 显示进度栏填充部分时也存在精确的问题。 也有几个使用嵌入的问题 iframe 元素,其中有些不是无关紧要的。 然后,我决定创建一个可以重用的ASP.NET 服务器控件来承载进度栏。 iPhone 7 还没出来,我们已经在iPhone上获取细节 8,或者不管是想到下一步。 span 元素有相同的缺点,所以我决定找一个更好的方法,开始研究 ASP.NET 条形图示例。 我决定使用HTTP处理程序和呈现"飞起来"的图像来使用相当健壮的解决方案。 这是我将在本文中描述的方法。

使用代码

我将在本节中介绍以下主题。

  • 基本服务器控件创建。
  • 进度栏服务器控件属性。
  • 呈现进度栏服务器控件。
  • 处理图像呈现"飞起来"的HTTP处理程序 CustomImageHandler
  • 使用服务器页上的进度栏。

基本服务器控件创建

创建一个派生自 System.Web.UI.WebControls.WebControl 并添加 使用 如下所示的语句:

using System;using System.Web.UI;using System.Web.UI.WebControls;using System.Web.UI.Design;using System.ComponentModel;using System.Drawing;using System.Drawing.Imaging;using System.Drawing.Design;using System.ComponentModel.Design;using System.ComponentModel.Design.Serialization;using System.IO;using System.Math;namespace YourNamespace
{
 publicclass ProgressBar : System.Web.UI.WebControls.WebControl
 {
 }
}

接下来,将以下属性添加到类文件的顶部( 在 使用 语句)。

[assembly: TagPrefix("YourNamespace", "ShortName")]

YourNamespaceShortName 替换为在项目中有意义的值。 这里属性控制可视化设计器将 inside 放置到 <@Register> 当从工具箱拖动服务器控件时在服务器页上的标记。 它允许一个更适合你的应用程序的命名方案。 我将使用进度栏节详细介绍这一点。

将下面的代码添加到类声明的顶部:

///<summary>/// This is the common graphical progress bar.///</summary>///<remarks>/// This custom control produces a graphical progress bar.///</remarks>[DefaultProperty("Type")]
[ToolboxData("<{0}:ProgressBar runat="server"></{0}:ProgressBar>")]
[ToolboxBitmapAttribute( typeof(ProgressBar) ) ]publicclass ProgressBar : System.Web.UI.WebControls.WebControl
{

你可以随意添加/替换注释代码 上面 以适合。

DefaultProperty 属性将 Type 属性声明为默认属性。 这允许你隐式引用该属性:

ProgressBar1 = BarType.Horizontal;

ToolboxData 属性声明工具箱将它的添加到页面时将添加到服务器页的文本。 iPhone 7 还没出来,我们已经在iPhone上获取细节 8,或者不管是想到下一步。 %7B0%7D 属性描述的一部分是该控件的已经注册命名空间的替换变量。 这是由 TagPrefix 属性控制的上面 属性。 当控件被拖放到服务器页上时,可视化设计器将添加以下内容:

<ShortName:ProgressBarid="ProgressBar1"runat="server"></ShortName:ProgressBar>

ToolboxBitmapAttribute 属性描述要在工具箱中显示的位图。 如果只提供类类型而没有 NAME,可视化设计器将在程序集中搜索该 NAME的16位x16位图。 你可以创建 16位x16位图并将它的作为嵌入资源添加到项目中,以表示控件,否则可视化设计器将使用默认位图。

现在,你有一个基本控件将在工具箱中呈现,并将在从工具箱拖动时正确填充你的服务器页面。 我将介绍如何使用进度栏部分将这里控件添加到你的工具箱中。 在下一节中,我将介绍如何将属性添加到进度栏控件。

进度栏服务器控件属性

下列属性已经被标识为基本进度栏呈现所必需的: TypeHeightWidthFillColorBackColorBorderBarSizeFillPercentFormat

Type 属性是指定的枚举,如下所示:

publicenum BarType
{
 Horizontal,
 Vertical
}

属性 HeightWidthBarSize 都是单位值类型,分别描述进度条的高度。宽度和内部大小。

FillPercent 是一个 浮点数 值,指定要显示的条的数量。

属性 BackColorFillColor 是无符号长值,分别指定 background 颜色和 bar/fill颜色。

属性 Format 是一个枚举值,指定如下:

publicenum BarFormat
{
 Gif,
 Jpeg,
 Png,
 Bmp
}

以下是这些属性的代码:

#region Private member variablesBarFormat format;
BarType type;bool border;
System.Drawing.Color fillColor;double fillPercent;
Unit barSize;#endregion#region Public properties[DefaultValue(BarFormat.Png), Category("ProgressBar Common"), 
 Description("Compression format for image.")]public BarFormat Format
{
 get { return format; }
 set { format = value; }
}
[DefaultValue(false), Category("ProgressBar Common"), 
 Description("Flag to show border or not.")]publicbool Border
{
 get { return border; }
 set { border = value; }
}
[DefaultValue(BarType.Horizontal), Category("ProgressBar Common"), 
 Description("Type of progress bar to render.")]public BarType Type
{
 get { return type; }
 set { type = value; }
}
[Category("ProgressBar Common"), 
 Description("Background color of progress bar.")]public System.Drawing.Color FillColor
{
 get { return fillColor; }
 set { fillColor = value; }
}
[DefaultValue(0.0), Category("ProgressBar Common"), 
 Description("Fill percentage of progress bar.")]publicdouble FillPercent
{
 get { return fillPercent; }
 set { fillPercent = value; }
}
[DefaultValue(0.0), Category("ProgressBar Common"), 
 Description("Size of progress bar inside frame")]public Unit BarSize
{
 get { return barSize; }
 set { barSize = value; }
}
[Browsable(false)]publicstring ContentType
{
 get { return"image/" + Format.ToString().ToLower(); }
}

最后一个属性 ContentType 被声明为不可浏览 可以浏览( false ) 属性。这里属性由HTTP处理程序CustomImageHandler节中描述的HTTP处理程序类使用。

呈现进度栏服务器控件

呈现 ASP.NET 服务器控件有两种模式。 第一个 DesignMode 提供控件的一种方法,它在可视化设计器中表示自身。 由于进度条控件包含动态渲染的图像,无法指定精确的表示,因此可以使用默认表示形式:

//Initial request for ProgressBar objectprotectedoverridevoid Render(HtmlTextWriter output)
{
 if (this.Site!= null && this.Site.DesignMode )
 {
 // Be careful to specify only html that// can be embedded in any tag. This will prevent// problems when displaying in the Visual Designer. output.Write(string.Format("<font size='1'" + 
 "color='SeaGreen' face='arial'>&nbsp;[ProgressBar::{0}]" + 
 "</font><br>", ID) );
 }

运行时呈现控件需要介绍下一主题- 使用HTTP处理程序处理在飞行时呈现的图像。 这里处理程序将拦截对某个网页的请求,该网页不存在,但在 <> 进度控制生成的标记。 在下一节中,我将详细介绍这个处理程序。 要生成的代码 <> 标记如下所示:

else{
 string uniqueName = GenerateUniqueName();
 Page.Application[ProgressBarRenderStream.ImageNamePrefix + uniqueName] = this;
 string toolTip = string.Format( "{0}", 
 Enabled? ((ToolTip == null || ToolTip == string.Empty)? 
 Round(FillPercent, 2).ToString()+"%" : ToolTip) : "");
 //Write relative URL for image stream request output.Write( 
 string.Format("<img src='{0}?id={1}'" + 
 "border='{2}' height='{3}' width='{4}' alt='{5}'>", 
 ProgressBarRenderStream.ImageHandlerRequestFilename, 
 uniqueName, (this.Border? "1" : "0"), 
 (int)this.Height.Value, (int)this.Width.Value, 
 toolTip );
}//Generates a new name for this control & registers string GenerateUniqueName()
{
 string sControlName = System.Guid.NewGuid().ToString();
 //Identifies requested ProgressBar imagereturn sControlName;
}

这里代码将生成一个唯一的NAME,它将标识当前呈现输出的进度栏类。 这个唯一的NAME 被用作 src 属性中 <> 标记,以允许HTTP处理程序在以后查找类。 值 ProgressBarRenderStream.ImageNamePrefixProgressBarRenderStream.ImageHandlerRequestFilename 在HTTP处理程序类中声明,将在下一节中进行说明。 这里代码应生成类似于以下( 值将根据属性值和生成的GUID值不同而不同)的HTML序列:

<imgsrc='image_stream.aspx?id=89f7f4ed-7433-460d-ae97-53c22aa2a232'border='1'height='8'width='128'alt='25.5%'>

这仍然不足以呈现控件。 以下函数将负责绘制进度条并将它的呈现到内存流:

public MemoryStream RenderProgressBar()
{
 try {
 if( Site!= null && Site.DesignMode )
 {
 string sType = this.Type.ToString();
 returnnull;
 }
 else {
 return makeProgressBar();
 }
 }
 catch {
 returnnull;
 }
}private MemoryStream makeProgressBar()
{
 // now convert percentage to width// (subtract 2 from width to adjust for border) Bitmap bmp = new Bitmap((int)Width.Value, 
 (int)Height.Value, PixelFormat.Format32bppArgb);
 MemoryStream memStream = new MemoryStream();
 Brush fillBrush = new SolidBrush( FillColor );
 Brush backgroundBrush = new SolidBrush( this.BackColor );
 // draw background System.Drawing.Graphics graphics = 
 Graphics.FromImage( bmp );
 graphics.FillRectangle(backgroundBrush, 0, 
 0, (int)Width.Value, (int)Height.Value);
 double fillAmount;
 if( this.Type == BarType.Horizontal )
 {
 // draw a horizontal bar// draw only BarSize height, centered vertically// inside the frame fillAmount = Width.Value * (FillPercent/100.0);
 graphics.FillRectangle(fillBrush, 0, 
 ((int)Height.Value - (int)BarSize.Value)/2, 
 (int)fillAmount, (int)BarSize.Value);
 }
 else {
 // draw a vertical bar// draw only BarSize width, centered horizontally// inside the frame fillAmount = Height.Value * (FillPercent/100.0);
 graphics.FillRectangle(fillBrush, 
 ((int)Width.Value - (int)BarSize.Value)/2, 
 (int)Height.Value-(int)fillAmount, 
 (int)BarSize.Value, (int)Height.Value);
 }
 graphics.Save();
 System.Drawing.Imaging.ImageFormat imgformat = 
 System.Drawing.Imaging.ImageFormat.Png;
 switch( Format )
 {
 case BarFormat.Bmp:
 imgformat = ImageFormat.Bmp;
 break;
 case BarFormat.Gif:
 imgformat = ImageFormat.Gif;
 break;
 case BarFormat.Jpeg:
 imgformat = ImageFormat.Jpeg;
 break;
 case BarFormat.Png:
 imgformat = ImageFormat.Png;
 break;
 }
 // Render BitMap Stream Back To Client bmp.Save(memStream, imgformat);
 return memStream;
}

这里代码将由 ProgresBarRenderStream 类调用,类将在下一节中。

使用HTTP处理程序动态呈现图像

为了动态地呈现图像,需要拦截HTTP请求并查找一个不存在的特定网页。 这里网页 NAME 是在呈现过程中由进度栏服务器控件指定的。 HTTP处理程序在检测到"特殊"网页后将从查询字符串中找到该值。 处理程序可以使用此值来查找请求的进度栏控件,以便在飞行时进行渲染。

有两步需要提供自定义的HTTP处理程序。 首先,创建一个从 IHttpModule 派生的类。 以下代码显示如下:

publicclass ProgressBarRenderStream : IHttpModule
{
 publicconststring ImageHandlerRequestFilename="image_stream.aspx";
 publicconststring ImageNamePrefix="i_m_g";
 public ProgressBarRenderStream()
 {
 }
 publicvirtualvoid Init( HttpApplication httpApp )
 {
 httpApp.BeginRequest += new EventHandler(httpApp_BeginRequest);
 }
 publicvirtualvoid Dispose()
 {
 }
 privatevoid httpApp_BeginRequest(object sender, EventArgs e)
 {
 HttpApplication httpApp = (HttpApplication)sender;
 ProgressBar pb = null;
 if( httpApp.Request.Path.ToLower().IndexOf(
 ImageHandlerRequestFilename)!= -1 )
 {
 pb = (ProgressBar)httpApp.Application[ImageNamePrefix + 
 (string)httpApp.Request.QueryString["id"]];
 if( pb == null )
 {
 return; // 404 will be returned }
 else {
 try {
 System.IO.MemoryStream memStream = pb.RenderProgressBar();
 memStream.WriteTo(httpApp.Context.Response.OutputStream);
 memStream.Close();
 httpApp.Context.ClearError();
 httpApp.Context.Response.ContentType = pb.ContentType;
 httpApp.Response.StatusCode = 200;
 httpApp.Application.Remove(ImageNamePrefix + 
 (string)httpApp.Request.QueryString["id"]);
 httpApp.Response.End();
 }
 catch(Exception ex)
 {
 ex = ex;
 }
 }
 }
 }
}

代码 上面 演示了 ProgressBar 控件在呈现时使用的共享值。 <> 然后,在 httpApp_BeginRequest 函数中使用这些值,这些值在 Init 函数中注册:

httpApp.BeginRequest += new EventHandler(httpApp_BeginRequest);

最后需要的步骤是将HTTP处理程序添加到web配置文件中。 这必须添加到 root 级别的web配置文件中才能正常工作。

<httpModules><addname="ProgressBarRenderStream"type="YourNamespace.ProgressBarRenderStream,YourAssemblyName"/></httpModules>

使用服务器页上的进度栏

使用服务器页面上的进度栏很容易。 首先,在项目文件中添加对控件的引用。 接下来,将下面的指令添加到服务器页面的顶部:

<%@RegisterTagPrefix="ShortName"Namespace="YourNamespace"Assembly="YourAssemblyName"%>

最后,将控件添加到页面,并将参数更改为:

<ShortName:ProgressBarid="ProgressBar1"runat="server"></ShortName:ProgressBar>

结束语

我开始研究我的问题有一个简单的解决方案- 提供一个直接反馈,使用图形表示。 进一步挖掘,我意识到,对于服务器控件来说,在不损害站点安全的情况下,我要做的是非常困难的。 进一步的研究使我找到了处理动态渲染图像的HTTP处理程序方法。 这种方法是强大的,可以扩展到其他应用程序,只限于你的想象力。


相关文章