ASP.NET的更高效的AJAX进度栏

分享于 

49分钟阅读

Web开发

  繁體
介绍

在 ASP.NET 中,当系统执行长时间运行的过程时,开发人员将要求显示进程的状态。 本文介绍了更高效的Ajax进度栏,它显示完成或者定制的消息。 基于 ASP.NET 服务器控制结构的控件,使用 jQuery ( 版本 1.9.1 ) 作为JavaScript库,对 Firefox。Chrome 和 IE 进行处理。

背景

在过去几年的开发中,我经常面对如何显示长期运行过程状态的问题。 我以前的经验是,我使用定时器向服务器发出请求,并返回信息。 虽然它可以解决这个问题,但性能却不好。 如果页面有多个控件,并且有超过 10个并发用户操作,那么页面的视图状态是 terrible,这是一个可怕的事情。 另外,编写JavaScript方法以使用web方法检索流程信息,以提高性能,但需要编写代码中的JavaScript方法( 例如 )。 XX.aspx. cs ),你需要使用进度条,这是低内聚性,并且不仅维护js代码,也不仅仅是服务器。 所有这些问题都是由 ASP.NET 架构引起的。 为了解决这个问题,我从MSDN和 finally 找到了一个要解决的技术,即定制的Ajax服务器控件。 更多内容,进度栏是由一些实际项目实现的,并赢得了许多 appreciations。

功能

  • 更有效。使用Ajax调用检索进程的信息。
  • 自定义每个呼叫的间隔。
  • 允许在同一页上放置多个进度栏并同步启动。
  • 自定义显示消息。
  • 在完成进程后可以添加sever事件。
  • 高内聚。控件中嵌入的JavaScript代码和CSS样式。
  • 可以使用JS启动进度栏。
  • 由 WCF,网络服务或者rest式服务完成的百分比检索。
  • 允许用户自定义模板以显示进程信息。 ( 2013-10-06 )

目前未包含。

  • 允许用户自定义模板以显示进程信息。
  • 暂停进度栏,然后继续。

使用代码

首先,我必须确保如果你想使用我的控件,你的"ASP.NET HTTP处理程序会有很好的知识。 如果你如何实现接口以及它的工作原理,你可以将这里部分分割为。

to ASP.NET HTTP处理程序是在响应对 ASP.NET Web应用程序的请求时运行的进程( 通常被称为"端点")。 最常见的处理程序是处理. aspx 文件的ASP.NET 页面处理程序。 当用户请求. aspx 文件时,请求由页面通过页面处理程序处理。 你可以创建自己的HTTP处理程序,将自定义输出呈现到浏览器。"

上语句由MSDN定义,请注意最后一句话"你可以创建自己的HTTP处理程序,将自定义输出呈现到浏览器。"开发人员可以通过扩展HTTP处理程序和"λ"is我们需要的接口。

IHttpHandler命令行接口。

这里接口中有一个属性和一个方法。

/// Property : IsReusablepublicbool IsReusable
{
 // Return false in case your Managed Handler cannot be reused for another request.// Usually this would be false in case you have some state information preserved per request.get { returntrue; }
}/// Method : ProcessRequestpublicvoid ProcessRequest(HttpContext context)
{
 //write your handler implementation here.}
  • <a href="http://msdn.microsoft.com/en-us/library/system.web.ihttphandler.isreusable.aspx">IsReusable</a> :评论。如果 IsReusable,每个请求都有单独的信息,否则,将相同的信息共享到其他请求。 但我还没改为"false"。 因为我不信任处理程序存储的内容,我只信任使用 QueryString 从URL发送的内容。
  • <a href="http://msdn.microsoft.com/en-us/library/system.web.ihttphandler.processrequest.aspx">ProcessRequest</a> :描述如何处理请求和响应输出。 这就是我们需要实现的。 让我们来描述一下如何实现 IHttpHandler插件。
using System;using System.Web;using System.Linq;using System.Collections.Generic;namespace ABC
{
 publicclass IISHandler: IHttpHandler
 {
 #region IHttpHandler Memberspublicbool IsReusable
 {
 // Return false in case your Managed Handler cannot be reused for another request.// Usually this would be false in case you have some state information preserved per request.get { returntrue; }
 }
 publicvoid ProcessRequest(HttpContext context)
 {
 //write your handler implementation here.string outputName = "Wells";
 List<string> QueryStringKeyList = context.Request.QueryString.AllKeys.ToList();
 if (QueryStringKeyList.Contains("name") &&!string.IsNullOrWhiteSpace(context.Request.QueryString["name"]))
 {
 outputName = context.Request.QueryString["name"];
 }
 HttpResponse Response = context.Response;
 Response.Write("<html>");
 Response.Write("<body>");
 Response.Write("<h1>Hello!" + outputName + ".</h1>");
 Response.Write("</body>");
 Response.Write("</html>");
 }
 #endregion }
}

在前面的示例中,我定义了一个名为"outputname"的变量并将"井"指定为默认值,然后如果URL没有名为"姓名"或者空的值。 井,"到浏览器,否则响应"你好 ! "+ NAME +"。"到浏览器。

处理程序实现之后,必须将一个HTTP处理程序添加到应用程序中,以便它能够捕获请求。

打开 Web.Config 文件并创建httpHandlers节。 注意:禁止使用保留字作为扩展名,比如 XXX.aspx, XXX.asmx, XXX.cs, XXX.svc, XXX.xaml, XXX.cshtml 等。 一般情况下,我们设置 XXX.ashx.

<configuration>
 <system.web>
 // IIS 6.0 <httpHandlers>
 <add verb="*" path="HelloHandle.ashx" type="ABC.IISHandler"/>
 </httpHandlers></system.web> <system.webServer>
 // IIS 7.0 <handlers>
 <add name="HelloHandle_ashx" path="HelloHandle.ashx" verb="*" type="ABC.IISHandler"/>
 </handlers></system.webServer></configuration>

最后,我们构建项目并在浏览器中进行测试。 打开浏览器并根据你的IIS设置键入 http://XXXX/HelloHandle.ashx. 替换"xxxx"。

Diagram1: 没有 QueryString的URL


Diagram2: 带有 QueryString的URL


所以在第一部分之后,我相信你可以自己创建http处理程序。 如果你还不明白我建议你做一些测试。 接下来,我们将开始学习如何使用进度栏。 我将用五个样本来描述这个话题。 从简单到困难,我们将研究最简单的第一个。

简单用法:

1.打开dbo或者 VS2012,创建名为,的ASP.NET web应用程序,这里将"coolservercontroltester"设为名称。

2.将进度栏控件导入到项目中。 dll文件被放置在名为"lib"的文件夹中。

3。创建名为" progressbartester.aspx"的新网页 form(.aspx),你也可以重命名它。

4.register 页中的控件。

<%@RegisterAssembly="CoolServerControl"Namespace="CoolServerControl"TagPrefix="wellsControl"%>

5.在页面中定义 updatepanel。

<asp:UpdatePanel ID="UP1" runat="server" UpdateMode="Conditional"> <ContentTemplate>
. . .........
 </ContentTemplate></asp:UpdatePanel>

6.将"进程"按钮和标签添加到updatepanel中。

<asp:UpdatePanel ID="UP1" runat="server" UpdateMode="Conditional"> <ContentTemplate>
 <div style="font: bold 12px arial;"> Simple Progress Bar:
 </div> <div style="float: left; width: 410px;"> <wellsControl:CoolProgressBar runat="server" ID="SimpleProgressBar" Height="20" Width="400" Interval="100" HideProgressBar="false" DefaultEmptyText="Press Process Button To Start The ProgressBar" RequestUrl="~/ProgressBarHandler_Simple.ashx" LabelLayout="Left"/>
 </div> <div style="float: left;"> <asp:Button runat="server" ID="ProcessBtn" Height="22" Text="Process Button"/>
 </div> <div style="float: left; font: bold 12px arial; line-height: 22px;" runat="server" id="label1"></div></ContentTemplate></asp:UpdatePanel>

7.将进度条放置到UpdatePanel中。

<wellsControl:CoolProgressBar runat="server" ID="SimpleProgressBar" Height="20" Width="400" Interval="100" HideProgressBar="false" DefaultEmptyText="Press Process Button To Start The ProgressBar" RequestUrl="~/ProgressBarHandler_Simple.ashx" LabelLayout="Left"/>
这里有一些属性:
  • Interval: 指示进度栏调用的每个请求之间的间隔毫秒。
  • HideProgressBar: 指定进度条是否在页 onload 中显示或者不显示。 默认为 true,这意味着在页onload时不显示进度栏。
  • DefaultEmptyText: 指定进度条中的默认消息。
  • LabelLayout: 确定消息的水平对齐方式。 "左","中心"还有"右"。默认值为"中心"。
  • RequestUrl: 提供一个 relative url来接收来自http处理程序的信息。

:: 在属性"updatemode"的"有条件的"中使用 UpdatePanel is包装进度栏,以便在单击进程按钮时,只发送UpdatePanel的子控件。 在这种情况下,我可以同时触发它的他进度条( 其他示例),并且不需要发布所有页面。

8.打开文件后面的代码。

9.按下按钮时将事件分配给进程按钮。

ProcessBtn.Click += ProcessBtn_Click;void ProcessBtn_Click(object sender, EventArgs e)
{
 SimpleProgressBar.ProgressBarGuid = Guid.NewGuid().ToString();
 label1.InnerText = "";
 SimpleProgressBar.StartProgressBar();
 ProcessBtn.Enabled = false;
}

在事件方法中,我们为进度栏分配了唯一的GUID。 然后清除标签。 finally,触发进度条以运行。

10.实现 IHttpHandler命令行接口以接收进度栏所做的调用。 如何实现 IHttpHandler插件及其上面提到的工作方式的详细信息。 你可以查看第一部分或者打开本文附带的示例来提醒你的记忆。

publicclass ProgressBarHandler_Simple : IHttpHandler
{
 #region IHttpHandler Memberspublicbool IsReusable
 {
 // Return false in case your Managed Handler cannot be reused for another request.// Usually this would be false in case you have some state information preserved per request.get { returntrue; }
 }
 publicvoid ProcessRequest(HttpContext context)
 {
 int processedCount = Convert.ToInt32(context.Request["ProcessedCount"]);
 //Dummyint totalCount = 500;
 CoolProgressBarStatus progressBarStatus = new CoolProgressBarStatus(context.Request["ProcessDateTime"].ToString(), context.Request["DatetimeFormat"].ToString(), processedCount + 1, totalCount, Math.Round(((double)processedCount * 100)/totalCount, 2, MidpointRounding.AwayFromZero) + "%");
 context.Response.ContentType = "text/xml";
 if (progressBarStatus!= null)
 {
 context.Response.Write(progressBarStatus.Serialize().OuterXml);
 }
 context.Response.Flush();
 }
 #endregion}

这里方法提供给进度栏以从每个请求获取进程的最新状态。 你可以通过URL从请求中获得一些 QueryString。

: )

~/ProgressBarHandler_Simple.ashx?ProcessDateTime=20131004182640&DatetimeFormat=yyyyMMddHHmmss&ProgressBarGuid=de0fcf4e-83d5-4cd7-9d95-85070c7a4081&Percentage=12.8&RandomKey=42588146267260&ProcessedCount=64&TotalCount=500

  • ProcessDatetime: 描述进程开始时间。
  • DatetimeFormat: 描述日期时间的格式。
  • ProgressBarGuid: 进程的唯一键。
  • Percentage: 当前完成百分比。
  • RandomKey: 避免获取浏览器的缓存( 2013-09-18编辑)
  • ProcessedCount: 已经处理的计数。
  • TotalCount: 进程的总计数。

在前面的代码段中,我根据 QueryString 值创建了一个CoolProgressBarStatus实例。 嵌入在控件中的CoolProgressBarStatus用于分组进程状态信息,并将它的序列化为用于进度条的XML格式。 ProcessRequest执行 它包含了总数。处理计数。进程开始时间和经过的时间等许多属性。 为了简单起见,我硬编码总数为 500,并将 1添加到每个请求处理的计数。

1.在 web.config 中的处理程序。

<system.web>
 <compilation debug="true" defaultLanguage="c#" targetFramework="4.0"/>
 <httpHandlers>
 <add path="ProgressBarHandler_Simple.ashx" verb="*" type="CoolServerControlTester.ProgressBarHandler_Simple" validate="false"/>
 </httpHandlers></system.web>

12.完成过程时将事件添加到进度条。

SimpleProgressBar.OnCompleted += new CoolServerControl.CoolProgressBar.Completed(SimpleProgressBar_OnCompleted);void SimpleProgressBar_OnCompleted(CoolServerControl.CoolProgressBar coolProgressBar, Guid progressBarGuid)
{
 label1.InnerText = "Process Completed!" + getCompleteMsg(coolProgressBar);
 ProcessBtn.Enabled = true;
}privatestring getCompleteMsg(CoolServerControl.CoolProgressBar progressbar)
{
 return getCompleteMsg(progressbar.ProgressBarGuid, progressbar.ProcessStartTime, progressbar.ProcessEndTime, progressbar.TotalCount, progressbar.ProcessedCount);
}privatestring getCompleteMsg(string uniqueKey, DateTime startDatetime, DateTime endDatetime, int totalCount, int processedCount)
{
 string reStr = "";
 reStr += " Unique Key :";
 reStr += uniqueKey.ToString();
 reStr += " Start Time :";
 if (startDatetime!= null && startDatetime!= new DateTime())
 {
 reStr += startDatetime.ToString("yyyy-MM-dd hh:mm:ss");
 }
 reStr += " End Time :";
 if (endDatetime!= null && endDatetime!= new DateTime())
 {
 reStr += endDatetime.ToString("yyyy-MM-dd hh:mm:ss");
 }
 reStr += " Total Count :";
 reStr += totalCount.ToString();
 reStr += " Processed Count :";
 reStr += processedCount.ToString();
 return reStr;
}

13.按F5运行。

在下面的示例中,我们将深入了解如何使用WCF服务使用进度栏。 让我们refresh并继续。

使用WCF调用的进度栏

首先,我们将创建WCF服务项目并在其中添加一些操作。

浏览VS2010中顶部菜单的"file-> Add-> 新项目。"。

选择"wcf服务应用程序"作为项目模板,并向项目提供 NAME。

删除由项目模板创建的原始服务并添加一个名为" progressbarser.svc"的新wcf服务。

将三个操作添加到服务中。

  • StartProcess(Guid guid): 使用唯一密钥启动长时间运行的进程。 ( 单向消息交换 Pattern )
  • GetProcessPrecentage(Guid guid): 使用唯一密钥获取进程状态。
  • ProcessComplete(Guid guid): 进程完成后服务器内存中的Delete 进程状态。

我们创建一个名为"ProcessStatus"的类来存储服务状态,并对它的应用 DataContract

[DataContract]publicclass ProcessStatus
{
 privateint _processedCount = 0;
 [DataMember(EmitDefaultValue = false)]
 public DateTime StartTime
 {
 get;
 set;
 }
 [DataMember(EmitDefaultValue = false)]
 public DateTime EndTime
 {
 get;
 set;
 }
 [DataMember(EmitDefaultValue = false)]
 publicint TotalCount
 {
 get;
 set;
 }
 [DataMember(EmitDefaultValue = false)]
 publicint ProcessedCount
 {
 get {
 return _processedCount;
 }
 set {
 _processedCount = value;
 }
 }
}

为了管理进程的所有状态,我们创建了一个名为"ProcessManager"的static 类。

publicstaticclass ProcessManager
{
 privatestaticobject sysLock = newobject();
 publicstatic Dictionary<Guid, ProcessStatus> ProcessList = new Dictionary<Guid, ProcessStatus>();
 publicstatic T GetPercentage<T>(Guid guid) where T : ProcessStatus
 {
 T temp = null;
 if (ProcessList.ContainsKey(guid))
 {
 temp = (T)ProcessList[guid];
 }
 return temp;
 }
 publicstaticvoid Process_Start<T>(Guid guid, int totalCount) where T : ProcessStatus
 {
 T processStatus = Activator.CreateInstance<T>();
 lock (sysLock)
 {
 if (ProcessList.ContainsKey(guid))
 {
 ProcessList.Remove(guid);
 }
 processStatus.StartTime = DateTime.Now;
 processStatus.TotalCount = totalCount;
 ProcessList[guid] = processStatus;
 }
 }
 publicstaticvoid Process_Update<T>(Guid guid, Action<T> action = null) where T : ProcessStatus
 {
 lock (sysLock)
 {
 if (ProcessList.ContainsKey(guid))
 {
 ((T)ProcessList[guid]).ProcessedCount++;
 if (action!= null)
 {
 action(((T)ProcessList[guid]));
 }
 }
 }
 }
 publicstaticvoid Process_Complete(Guid guid)
 {
 lock (sysLock)
 {
 if (ProcessList.ContainsKey(guid))
 {
 ProcessList.Remove(guid);
 }
 }
 }
}

在前一段代码中,我们创建一个 static 字典插件来存储所有进程状态,以便我们可以通过惟一键来获取进程状态。 另一方面,我们创建了一个 static 对象,通过锁定它来确保代码的block 运行完成而不会中断。

实现接口中的三个抽象方法。

publicvoid StartProcess(Guid guid)
{
 //Hard-code total count of the process to 200.int totalCount = 200;
 //Initial a new process's status. ProcessManager.Process_Start<ProcessStatus>(guid, totalCount);
 for (int i = 0; i < totalCount; ++i)
 {
 //As demonstration, suspend current thread for 0.1 second. Thread.Sleep(100);
 //Update processed count. ProcessManager.Process_Update<ProcessStatus>(guid);
 }
}public ProcessStatus GetProcessPrecentage(Guid guid)
{
 ProcessStatus processStatus = ProcessManager.GetPercentage<ProcessStatus>(guid);
 return processStatus;
}publicvoid ProcessComplete(Guid guid)
{
 //Remove process's status by unique key after process completed so that free the memory. ProcessManager.Process_Complete(guid);
} 

向服务部分添加服务终结点和服务行为,以及WCF服务的行为。

<services>
 <service behaviorConfiguration="MyServiceBehavior" name="WCFService.ProgressBarSer"> <endpoint address="" binding="basicHttpBinding" bindingConfiguration="" contract="WCFService.IProgressBarSer"/>
 <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
 </service></services><behaviors>
 <serviceBehaviors>
 <behavior name="MyServiceBehavior"> <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint 上面 before deployment -->
 <serviceMetadata httpGetEnabled="true"/>
 <!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
 <serviceDebug includeExceptionDetailInFaults="false"/>
 </behavior></serviceBehaviors></behaviors>

返回 ASP.NET 项目并添加上面提到的服务引用。

创建一个实现名为的接口的类,以从WCF服务获得进程状态。

publicclass ProgressBarHandler_WCF : IHttpHandler
{
 #region IHttpHandler Memberspublicbool IsReusable
 {
 // Return false in case your Managed Handler cannot be reused for another request.// Usually this would be false in case you have some state information preserved per request.get { returntrue; }
 }
 publicvoid ProcessRequest(HttpContext context)
 {
 string guid = context.Request["ProgressBarGuid"].ToString();
 CoolServerControlTester.ProgressBarSer.ProcessStatus processStatus = null;
 using (ProgressBarSerClient progressBarClient = new ProgressBarSerClient())
 {
 processStatus = progressBarClient.GetProcessPrecentage(Guid.Parse(guid));
 }
 CoolProgressBarStatus progressBarStatus = new CoolProgressBarStatus(DateTime.Now, 0, 100);
 if (processStatus!= null)
 {
 progressBarStatus = new CoolProgressBarStatus(context.Request["ProcessDateTime"].ToString(), context.Request["DatetimeFormat"].ToString(), processStatus.ProcessedCount, processStatus.TotalCount);
 progressBarStatus.MsgText = (Math.Round(Convert.ToDouble(processStatus.ProcessedCount)/processStatus.TotalCount * 100, 2, MidpointRounding.AwayFromZero)) + "%(" + processStatus.ProcessedCount + "/" + processStatus.TotalCount + ")" + progressBarStatus.ElapsedTimeStr;
 }
 context.Response.ContentType = "text/xml";
 if (progressBarStatus!= null)
 {
 context.Response.Write(progressBarStatus.Serialize().OuterXml);
 }
 context.Response.Flush();
 }
 #endregion}

register 应用程序的处理程序。

<system.web>
 <compilation debug="true" defaultLanguage="c#" targetFramework="4.0"/>
 <httpHandlers>
 <add path="ProgressBarHandler_Simple.ashx" verb="*" type="CoolServerControlTester.ProgressBarHandler_Simple" validate="false"/>
 <add path="ProgressBarHandler_WCF.ashx" verb="*" type="CoolServerControlTester.ProgressBarHandler_WCF" validate="false"/></httpHandlers></system.web>

在. aspx 页中插入一个与第一个示例相同的新进度栏。

将按钮单击事件添加到按钮,并在页面加载时将已经完成的事件添加到进度栏。

protectedvoid Page_Load(object sender, EventArgs e)
{
 #region [ Simple Progress Bar ] ProcessBtn.Click += ProcessBtn_Click;
 SimpleProgressBar.OnCompleted += new CoolServerControl.CoolProgressBar.Completed(SimpleProgressBar_OnCompleted);
 #endregion#region [ WCF Progress Bar ] ProcessBtn_Wcf.Click += ProcessBtn_Wcf_Click;
 WCFProgressBar.OnCompleted += WCFProgressBar_OnCompleted;
 #endregion}#region [ WCF Progress Bar Event ]void WCFProgressBar_OnCompleted(CoolServerControl.CoolProgressBar coolProgressBar, Guid progressBarGuid)
{
 label2.InnerText = "Process Completed!" + getCompleteMsg(coolProgressBar);
 using (ProgressBarSerClient progressBarClient = new ProgressBarSerClient())
 {
 progressBarClient.ProcessComplete(Guid.Parse(coolProgressBar.ProgressBarGuid));
 } ProcessBtn_Wcf.Enabled = true;
}void ProcessBtn_Wcf_Click(object sender, EventArgs e)
{
 WCFProgressBar.ProgressBarGuid = Guid.NewGuid().ToString();
 label2.InnerText = "";
 WCFProgressBar.StartProgressBar();
 using (ProgressBarSerClient progressBarClient = new ProgressBarSerClient())
 {
 progressBarClient.StartProcess(Guid.Parse(WCFProgressBar.ProgressBarGuid));
 } ProcessBtn_Wcf.Enabled = false;
}#endregion

在前面的代码段中,我们使用由 Visual Studio 自动生成的代理类来使用 WCF serivces。 但是,你也可以手动定义动态代理类,这样做比原来的更灵活,但是我不希望深入到更深入的WCF类。

按F5运行。


在前两个示例中,我演示了进度条的基本用法,我认为你有很多关于如何在解决方案中使用进度条的想法。 但是请记住这些想法并跟随我来学习下一个关于如何使用JavaScript来触发进度栏的示例。 我认为当你从JavaScript打电话时它很有用。

通过Javascript工作的进度栏触发器与WCF调用

在以下示例中,我将使用jQeury库来执行演示文稿,而不是编写太多脚本。

  • 在这里下载jQuery库表单( )。 在我的示例中,版本没有。 jQuery是 1.9.1,使用最新版本不是问题。 然后将刚才下载的文件放入到你的解决方案中。 我曾经创建一个Js文件夹来存储 Js,并在它中创建一个名为"公用"的子文件夹,用于存储Js库和。
  • 在页面上包含js文件。
<scriptlanguage="javascript"src="Js/common/jquery-1.9.1.min.js"type="text/javascript"></script>
  • 将进度栏作为示例 1和示例 2放置到测试页中。
<asp:UpdatePanel ID="UpdatePanel2" runat="server" UpdateMode="Conditional"> <ContentTemplate>
 <div style="font: bold 12px arial;"> Progress Bar Triggered By Javascript Work With WCF Call :
 </div> <div style="float: left; width: 410px;"> <wellsControl:CoolProgressBar runat="server" ID="JSProgressBar" Height="20" Width="400" Interval="100" HideProgressBar="false" DefaultEmptyText="Press Process Button To Start The ProgressBar" RequestUrl="~/ProgressBarHandler_WCF.ashx"/>
 </div> <div style="float: left;"><input name="jsButton" type="button" id="jsButton" style="height: 22px;"value="Process by Javascript" onclick="CallWcfByJS(this,'JSProgressBar','label3');"/></div> <div style="float: left; font: bold 12px arial; line-height: 22px;" runat="server" id="label3"></div></ContentTemplate></asp:UpdatePanel>

请注意 Highlight,按钮不是服务器控制,我们将客户端 onclick 事件添加到它。 事件的细节将在以下内容中提到。

  • 创建一个JS函数来处理事件。
function CallWcfByJS(sender, progressBarID, labelID) {
 var guid = GenGUID();
 $.ajax({
 url: "http://localhost:50066/ProgressBarJsSer.svc/StartProcessJS/" + guid,
 type: "GET",
 dataType: "jsonp",
 crossDomain: true });
 $("#" + labelID).text("");
 $("#" + progressBarID)[0].control.set_ProgressBarGuid(guid);
 $("#" + progressBarID)[0].control.OnProgressBarStart();
 $(sender).attr("disabled", "disabled");
 var jsCompleteFun = function () {
 $(sender).removeAttr("disabled");
 }
 $("#" + progressBarID)[0].control.set_JsCompleteEvent(jsCompleteFun);
} 

在前面的代码段中,我们使用预定义函数创建一个惟一的键。 然后,我们对WCF的rest式服务进行Ajax调用以启动新流程。 $.ajax 是jQuery中的AJAX方法,默认情况下执行异步调用,因此系统不需要等到响应返回时才需要等待。 然后,清除标签的信息,禁用按钮,设置唯一键到进度条,并触发它运行。 最后,将客户端完成事件定义为进度条,这将在进度条完成后执行。

  • 在文件完成后,将进程添加到进度条时添加事件。
protectedvoid Page_Load(object sender, EventArgs e)
{
 #region [ Simple Progress Bar ] ProcessBtn.Click += ProcessBtn_Click;
 SimpleProgressBar.OnCompleted += new CoolServerControl.CoolProgressBar.Completed(SimpleProgressBar_OnCompleted);
 #endregion 
 #region [ WCF Progress Bar ] ProcessBtn_Wcf.Click += ProcessBtn_Wcf_Click;
 WCFProgressBar.OnCompleted += WCFProgressBar_OnCompleted;
 #endregion 
 #region [ Js Progress Bar ] JSProgressBar.OnCompleted += JSProgressBar_OnCompleted;#endregion}#region [ JS Progress Bar Event ]void JSProgressBar_OnCompleted(CoolServerControl.CoolProgressBar coolProgressBar, Guid progressBarGuid)
{
 label3.InnerText = "Process Completed!" + getCompleteMsg(coolProgressBar);
 using (ProgressBarSerClient progressBarClient = new ProgressBarSerClient())
 {
 progressBarClient.ProcessComplete(Guid.Parse(coolProgressBar.ProgressBarGuid));
 }
}#endregion 
  • 导航到WCF服务项目并通过单向消息交换 Pattern 添加rest式操作。
[ServiceContract]publicinterface IProgressBarJsSer
{
 [OperationContract(IsOneWay = true)]
 [WebGet(UriTemplate = "StartProcessJS/{guidStr}")]
 void StartProcess_JS(string guidStr);
} 
  • 实现接口。
publicclass ProgressBarJsSer : IProgressBarJsSer
{
 publicvoid StartProcess_JS(string guidStr)
 {
 Guid guid = Guid.Parse(guidStr);
 int totalCount = 100;
 ProcessManager.Process_Start<ProcessStatus>(guid, totalCount);
 for (int i = 0; i < totalCount; ++i)
 {
 Thread.Sleep(100);
 ProcessManager.Process_Update<ProcessStatus>(guid);
 }
 }
} 
  • 在 web.config 中配置rest式服务。
<services>
 <service behaviorConfiguration="MyServiceBehavior" name="WCFService.ProgressBarJsSer"> <endpoint address="" behaviorConfiguration="WebBehavior" binding="webHttpBinding" contract="WCFService.IProgressBarJsSer"/>
 <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
 </service></services><behaviors>
 <serviceBehaviors>
 <behavior name="MyServiceBehavior"> <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint 上面 before deployment -->
 <serviceMetadata httpGetEnabled="true"/>
 <!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
 <serviceDebug includeExceptionDetailInFaults="false"/>
 </behavior></serviceBehaviors> <endpointBehaviors>
 <behavior name="WebBehavior"> <webHttp/>
 </behavior></endpointBehaviors></behaviors>
  • 按"f5"键运行。

带有可以自定义信息的进度栏,可以与WCF调用一起使用

在下面的示例中,我将介绍如何根据模板定制进程信息。

  • 在测试页中添加进度条并设计模板以显示进程信息。
......
 <wellsControl:CoolProgressBar runat="server" ID="WCFProgressBarCT" Height="20" Visible="true" Width="400" Interval="100" HideProgressBar="false" DefaultEmptyText="Press Process Button To Start The ProgressBar" RequestUrl="~/ProgressBarHandler_WCF_CT.ashx"> <CustomizableTemplate>
 <div class="w-panel" style="width: 350px;"> <div class="w-panel-header"> Process Information
 </div> <div class="w-panel-body"> <div id="r1"class="w-panel-body-row"> <div class="w-panel-body-row-left"> Sequence No.
 </div> <div class="w-panel-body-row-right"> @SeqNo
 </div> <div style="clear: both;"></div></div> <div id="r2"class="w-panel-body-row-alt"> <div class="w-panel-body-row-left"> Create Time
 </div> <div class="w-panel-body-row-right"> @CreateTime
 </div> <div style="clear: both;"></div></div> <div id="r3"class="w-panel-body-row"> <div class="w-panel-body-row-left"> Amount
 </div> <div class="w-panel-body-row-right"> @Amount
 </div> <div style="clear: both;"></div></div> <div id="r4"class="w-panel-body-row-alt"> <div class="w-panel-body-row-left"> Total Price
 </div> <div class="w-panel-body-row-right"> @TotalPrice
 </div> <div style="clear: both;"></div></div></div></div></CustomizableTemplate></wellsControl:CoolProgressBar>...... 

在前面的代码段中,我们设计了一个网格来显示进程信息。 实际上,你可以先在另一页中设计自定义布局,然后将它的放入名为"customizabletemplate"。 将由进程信息的数据替换带有前缀"@"的单词。 在这里,我们声明 @SeqNo, @CreateTime, @Amount 和 @TotalPrice. 接下来,我们创建一个类来将这些日期存储在服务端。

  • 创建用于存储将返回到进度栏的可以自定义信息的DataContract。
[DataContract]publicclass OrderInfo
{
 privateconststring datetimeFormat = "yyyy-MM-dd HH:mm:ss";
 privatestring seqNo = "";
 private DateTime? createTime = null;
 privatedouble totalPrice = 0;
 privateint amount = 0;
 public OrderInfo(string seqNo, DateTime createTime, double totalPrice, int amount)
 {
 this.seqNo = seqNo;
 this.createTime = createTime;
 this.totalPrice = totalPrice;
 this.amount = amount;
 }
 [DataMember]
 publicstring SeqNo
 {
 get {
 return seqNo;
 }
 privateset {
 seqNo = value;
 }
 }
 [DataMember]
 publicstring CreateTime
 {
 get {
 return createTime.HasValue? createTime.Value.ToString(datetimeFormat) : ""; }
 privateset {
 DateTime dReturn;
 if (!DateTime.TryParseExact(value, datetimeFormat, null, DateTimeStyles.None, out dReturn))
 {
 }
 createTime = dReturn;
 }
 }
 [DataMember]
 publicstring TotalPrice
 {
 get {
 return totalPrice.ToString(); }
 privateset {
 totalPrice = Convert.ToDouble(value);
 }
 }
 [DataMember]
 publicstring Amount
 {
 get {
 return amount.ToString(); }
 privateset {
 amount = Convert.ToInt32(value);
 }
 }
} 

在前面的代码段中,我们创建一个名为"orderinfo"的类,其中有4 个属性。 所有这些属性类型都是字符串。 因为很难将对象自动转换为客户端的特定格式,然后在发送回客户端之前将数据转换为特定格式。

  • 使用ProcessStatus_Order创建一个名为的类,并将OrderInfo打包,这样使用该服务的用户不仅可以检索进程的基本信息,而且还可以获取来自它的可以自定义信息。
[DataContract][KnownType(typeof(OrderInfo))]publicclass ProcessStatus_Order : ProcessStatus
{
 [DataMember]
 public OrderInfo orderInfo
 {
 get;
 set;
 }
} 
  • 在服务合同中添加三个操作,以便演示如何在进程完成后使用自定义信息启动进程,获取进程信息和进程信息。
publicvoid StartProcess_CustomizableInfo(Guid guid)
{
 //Dummy Data List<OrderInfo> orderStatusList = new List<OrderInfo>();
 orderStatusList.Add(new OrderInfo("20130101102", new DateTime(2013, 1, 1), 1001.01, 1));
. . ......
 orderStatusList.Add(new OrderInfo("20130111571", new DateTime(2013, 1, 11), 1011.01, 11));
 ProcessManager.Process_Start<ProcessStatus_Order>(guid, orderStatusList.Count);
 for (int i = 0; i < orderStatusList.Count; ++i)
 {
 Thread.Sleep(500);
 ProcessManager.Process_Update<ProcessStatus_Order>(guid, (orderStatus) => {
 orderStatus.orderInfo = orderStatusList[i];
 });
 }
}public ProcessStatus_Order GetProcessPrecentage_CustomizableInfo(Guid guid)
{
 ProcessStatus_Order processStatus = ProcessManager.GetPercentage<ProcessStatus_Order>(guid);
 return processStatus;
}publicvoid ProcessComplete_CustomizableInfo(Guid guid)
{
 ProcessManager.Process_Complete(guid);
} 

请注意 Highlight 代码,我们使用ProcessStatus_Order而不是 ProcessStatus。

  • 创建一个新的http处理程序来检索流程状态和可以自定义的信息表单,然后指定进程状态和可以自定义信息。 在 below 代码段中,我们序列化可以定制的信息( 例如。 OrderInfo ) 通过 JavaScriptSerializer to json格式,并将它分配给progressBarStatus的MagInJson属性。
publicclass ProgressBarHandler_WCF_CT : IHttpHandler
{
 #region IHttpHandler Memberspublicbool IsReusable
 {
 // Return false in case your Managed Handler cannot be reused for another request.// Usually this would be false in case you have some state information preserved per request.get { returntrue; }
 }
 publicvoid ProcessRequest(HttpContext context)
 {
 string guid = context.Request["ProgressBarGuid"].ToString();
 CoolServerControlTester.ProgressBarSer.ProcessStatus_Order processStatus = null;
 using (ProgressBarSerClient progressBarClient = new ProgressBarSerClient())
 {
 processStatus = progressBarClient.GetProcessPrecentage_CustomizableInfo(Guid.Parse(guid));
 }
 CoolProgressBarStatus progressBarStatus = new CoolProgressBarStatus(DateTime.Now, 0, 100);
 if (processStatus!= null)
 {
 progressBarStatus = new CoolProgressBarStatus(context.Request["ProcessDateTime"].ToString(), context.Request["DatetimeFormat"].ToString(), processStatus.ProcessedCount, processStatus.TotalCount);
 progressBarStatus.MsgText = (Math.Round(Convert.ToDouble(processStatus.ProcessedCount)/processStatus.TotalCount * 100, 2, MidpointRounding.AwayFromZero)) + "%(" + processStatus.ProcessedCount + "/" + processStatus.TotalCount + ")" + progressBarStatus.ElapsedTimeStr;
 progressBarStatus.MsgInJson = new JavaScriptSerializer().Serialize(processStatus.orderInfo)??99 ""; }
 context.Response.ContentType = "text/xml";
 if (progressBarStatus!= null)
 {
 context.Response.Write(progressBarStatus.Serialize().OuterXml);
 }
 context.Response.Flush();
 }
 #endregion} 
  • register 应用程序的处理程序。 有关详细信息,请查阅 上面 部分。
  • 将按钮单击事件添加到按钮,并在页面加载时将已经完成的事件添加到进度栏。
  • 按"f5"键运行。

进度栏,带有由 Javascript 触发的可以定制信息,使用

下面的示例与前面的示例类似。 但它由Javascript触发。

  • 向进度条中添加可以自定义的模板,并将客户端事件分配给按钮。
......
<wellsControl:CoolProgressBar runat="server" ID="JSProgressBarCT" Height="20" Visible="true" Width="400" Interval="100" HideProgressBar="false" DefaultEmptyText="Press Process Button To Start The ProgressBar" RequestUrl="~/ProgressBarHandler_TrialRun.ashx"> <CustomizableTemplate>
 <div class="w-panel" style="width: 350px;"> <div class="w-panel-header"> Process Information
 </div> <div class="w-panel-body"> <div id="r1"class="w-panel-body-row"> <div class="w-panel-body-row-left"> Employee No.
 </div> <div class="w-panel-body-row-right"> @EmpNo
 </div> <div style="clear: both;"></div></div> <div id="r2"class="w-panel-body-row-alt"> <div class="w-panel-body-row-left"> Last Hire Date
 </div> <div class="w-panel-body-row-right"> @LastHireDate
 </div> <div style="clear: both;"></div></div> <div id="r3"class="w-panel-body-row"> <div class="w-panel-body-row-left"> Salary
 </div> <div class="w-panel-body-row-right"> @Salary
 </div> <div style="clear: both;"></div></div></div></div></CustomizableTemplate></wellsControl:CoolProgressBar> 
......
<input type="button" id="jsButtonCT"value="Process Button" runat="server" onclick="CallWcfByJSWithCT(this, 'JSProgressBarCT', 'label5');"/> 

在这里,我添加了三个变量。 有 @EmpNo,@LastHireDate 和 @Salary.,然后将click事件附加到按钮。

  • 补充js函数的细节,它通过rest式服务启动一个进程。
function CallWcfByJSWithCT(sender, progressBarID, labelID) {
 var guid = GenGUID();
 $.ajax({
 url: "http://localhost:50066/ProgressBarJsSer.svc/TrialRun/" + guid,
 type: "GET",
 dataType: "jsonp",
 crossDomain: true });
 $("#" + labelID).text("");
 $("#" + progressBarID)[0].control.set_ProgressBarGuid(guid);
 $("#" + progressBarID)[0].control.OnProgressBarStart();
 $(sender).attr("disabled", "disabled");
 var jsCompleteFun = function () {
 $(sender).removeAttr("disabled");
 }
 $("#" + progressBarID)[0].control.set_JsCompleteEvent(jsCompleteFun);
} 
  • 创建一个DataContract来存储可以定制的信息。
[DataContract]publicclass EmployeeInfo
{
 privateconststring datetimeFormat = "dd/MM/yyyy";
 privatestring empNo = "";
 private DateTime? lastHireDate = null;
 privatedouble salary = 0;
 public EmployeeInfo(string empNo, DateTime lastHireDate, double salary)
 {
 this.empNo = empNo;
 this.lastHireDate = lastHireDate;
 this.salary = salary;
 }
 [DataMember]
 publicstringEmpNo {
 get {
 return empNo;
 }
 privateset {
 empNo = value;
 }
 }
 [DataMember]
 publicstringLastHireDate {
 get {
 return lastHireDate.HasValue? lastHireDate.Value.ToString(datetimeFormat) : "";
 }
 privateset {
 DateTime dReturn;
 if (!DateTime.TryParseExact(value, datetimeFormat, null, DateTimeStyles.None, out dReturn))
 {
 }
 lastHireDate = dReturn;
 }
 }
 [DataMember]
 publicstringSalary {
 get {
 return"$" + salary.ToString();
 }
 privateset {
 salary = Convert.ToDouble(value);
 }
 }
} 
  • 创建一个类以包装继承表单ProcessStatus的雇员信息。
[DataContract][KnownType(typeof(EmployeeInfo))]publicclass ProcessStatus_Employee : ProcessStatus
{
 [DataMember]
 public EmployeeInfo employeeInfo
 {
 get;
 set;
 }
} 
  • 创建一个http处理程序来检索可以。 ( 之前提到过。)
  • register 应用程序的处理程序。
  • 在页面加载时将已经完成的事件添加到进度栏。
. . .....
 #region [ JS Progress Bar with Customizable Template ] JSProgressBarCT.OnCompleted += new CoolServerControl.CoolProgressBar.Completed(JSProgressBarCT_OnCompleted);
 #endregion}#region [ JS Progress Bar with Customizable Template Event ]void JSProgressBarCT_OnCompleted(CoolServerControl.CoolProgressBar coolProgressBar, Guid progressBarGuid)
{
 label5.InnerText = "Process Complete!" + getCompleteMsg(coolProgressBar);
 using (ProgressBarSerClient progressBarClient = new ProgressBarSerClient())
 {
 progressBarClient.TrialRunComplete(coolProgressBar.ProgressBarGuid);
 }
}#endregion 
  • 按"f5"键运行。

至此,我已经介绍了进度栏的五种基本用法,你可以在附件中下载我的示例项目。 希望该控件能够帮助你改善用户体验,并希望你能够根据你的需求发现其他用途。 另外,我将继续改进这个控件,这里有一些特性,如前面提到的,希望你能够加入到控件中,因此希望你能跟踪本文,以获得更多的功能。 感谢你的阅读,如果你有任何问题,请随时联系我。 谢谢!

历史记录

  • 2013-09-07第一版版本。
  • 1 固定缓存问题。将随机数作为参数附加到相对 URL ( )。 ) 这样它就不会被缓存。 感谢 Marco !
  • 6 2013-10-06自定义模板以显示进程信息。
  • 2016-01-27修复显示问题Fullfill最新浏览器包括 IE 11,Chrome,Edge。

asp  asp-net  进度  进度条  
相关文章