在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
Building a Real Time ProgressBar using ASP.NET AtlasDflying | 27 March, 2006 23:44
That will be very cool and useful if you can show your user a ProgressBar on a web page which displays the actual progress of some long operations. Now let’s try to make it possible by using ASP.NET Atlas. This post can also show you some basic conceptions about extending Atlas client side controls. Also, the source code and demo can be downloaded here. The basic ideas to implement this will be easy. Build an Atlas client side control and query a service to find how much we’ve done every tick. Then get the response and update the UI of progress bar. So in this demo, we separate the code into four parts:
Let’s go through the four steps. Time Consuming Web Service In the real world, a time consuming function may runs like following:
[WebMethod] public void TimeConsumingTask() { ConnectToDataBase(); GetSomeValueFromDataBase(); CopySomeFilesFromDisk(); GetARemoteFile(); }
Then we can insert some helpers to show how much the work has been done:
[WebMethod] public void TimeConsumingTask() { setProgress(0); ConnectToDataBase(); setProgress(10); GetSomeValueFromDataBase(); setProgress(40); CopySomeFilesFromDisk(); setProgress(50); GetARemoteFile(); setProgress(100); }
In this demo we just store the progress value in Cache and use Thread.Sleep() to delay the processing:
[WebMethod] public int StartTimeConsumingTask() { string processKey = this.Context.Request.UserHostAddress; string threadLockKey = "thread" + this.Context.Request.UserHostAddress; object threadLock = this.Context.Cache[threadLockKey]; if (threadLock == null) { threadLock = new object(); this.Context.Cache[threadLockKey] = threadLock; } // Only allow 1 running task per user. if (!Monitor.TryEnter(threadLock, 0)) return -1; DateTime startTime = DateTime.Now; // Simulate a time-consuming task. for (int i = 1; i <= 100; i++) { // Update the progress for this task. this.Context.Cache[processKey] = i; Thread.Sleep(70); } Monitor.Exit(threadLock); return (DateTime.Now - startTime).Seconds; }
GetProgress Web Service This should be easy.We just get the progress value from Cache:
[WebMethod] public int GetProgress() { string processKey = this.Context.Request.UserHostAddress; object progress = this.Context.Cache[processKey]; if (progress != null) { return (int)progress; } return 0; }
Atlas ProgressBar control Step 1: Derive from Sys.UI.Control ProgressBar control should derive from the base Atlas control class, Sys.UI.Control and let’s make it a sealed class. The Sys.UI.Control base class contains some useful things, such as associating itself with an HTML element, which is the so called binding. Additionally, you should register your type to make it possible to instantiate it declaratively. Also register your class to let Atlas know it for further options, such as describing what the type is, etc.
Sys.UI.ProgressBar = function(associatedElement) { Sys.UI.ProgressBar.initializeBase(this, [associatedElement]); } Type.registerSealedClass('Sys.UI.ProgressBar', Sys.UI.Control); Sys.TypeDescriptor.addType('script','progressBar', Sys.UI.ProgressBar);
Step 2: Add private fields and the Setter/Getter We have to add some configurable properties for our control. In this case, we have 3 properties:
Properties have to follow an exact naming convention: the getter of the property should be a function prefixed with 'get_', and the setter should be prefixed with 'set_' and expect 1 parameter. Additionally, we should add these properties to our control's descriptor. Please see step 4 on how this should be done. For the service method property, we have following code:
var _serviceMethod; this.get_serviceMethod = function() { return _serviceMethod; } this.set_serviceMethod = function(value) { _serviceMethod = value; }
Step 3: Add a Timer to query the service on every tick Here we include a Sys.Timer to query the service. Also define a delegate to represent the function that we want the timer to invoke on each tick. To get rid of the browser memory leak, we should make sure to finish the clean up when our control is disposing.
var _timer = new Sys.Timer(); var _responsePending; var _tickHandler; var _obj = this; this.initialize = function() { Sys.UI.ProgressBar.callBaseMethod(this, 'initialize'); _tickHandler = Function.createDelegate(this, this._onTimerTick); _timer.tick.add(_tickHandler); this.set_progress(0); } this.dispose = function() { if (_timer) { _timer.tick.remove(_tickHandler); _tickHandler = null; _timer.dispose(); } _timer = null; associatedElement = null; _obj = null; Sys.UI.ProgressBar.callBaseMethod(this, 'dispose'); } this._onTimerTick = function(sender, eventArgs) { if (!_responsePending) { _responsePending = true; // Asynchronously call the service method. Sys.Net.ServiceMethod.invoke(_serviceURL, _serviceMethod, null, null, _onMethodComplete); } } function _onMethodComplete(result) { // Update the progress bar. _obj.set_progress(result); _responsePending = false; }
Step 4: Add control methods We should be able to start/stop our progress bar. And since this control is an Atlas object, we want it be known by the Atlas framework by describing its methods in the descriptor.
this.getDescriptor = function() { var td = Sys.UI.ProgressBar.callBaseMethod(this, 'getDescriptor'); td.addProperty('interval', Number); td.addProperty('progress', Number); td.addProperty('serviceURL', String); td.addProperty('serviceMethod', String); td.addMethod('start'); td.addMethod('stop'); return td; } this.start = function() { _timer.set_enabled(true); } this.stop = function() { _timer.set_enabled(false); }
Oh… till now, the control’s done! Save it as ProgressBar.js.
ASP.NET Testing Page Of course, the first step of building every Atlas page is adding a ScriptManager server control. In this case we refer to our ProgressBar control, time consuming web service and GetProgress web service. (The two web services are located in one file: TaskService.asmx)
<atlas:ScriptManager ID="ScriptManager1" runat="server" > <Scripts> <atlas:ScriptReference Path="ScriptLibrary/ProgressBar.js" ScriptName="Custom" /> </Scripts> <Services> <atlas:ServiceReference Path="TaskService.asmx" /> </Services> </atlas:ScriptManager>
Then styles and layouts:
<style type="text/css"> * { font-family: tahoma; } .progressBarContainer { border: 1px solid #000; width: 500px; height: 15px; } .progressBar { background-color: green; height: 15px; width: 0px; font-weight: bold; } </style> <div>Task Progress</div> <div class="progressBarContainer"> <div ></div> </div> <input type="button" value="Start the Time Consuming Task!" /> <div ></div>
At last is the JavaScript event handler which makes the ProgressBar control ran.
<script type="text/javascript" language="javascript"> function startTask() { // new ProgressBar var pb = new Sys.UI.ProgressBar($('pb')); pb.set_interval(500); pb.set_serviceURL('TaskService.asmx'); pb.set_serviceMethod('GetProgress'); pb.initialize(); // start the task TaskService.StartTimeConsumingTask(onTaskCompleted); // start the ProgressBar pb.start(); } function onTaskCompleted(result) { // alert the time cost if (result != -1) $('output').innerHTML = 'Task completed in ' + result + ' seconds.'; } </script>
Screen Shots and Download Great, everything’s done now! Let’s run it! Not started: Running: Completed: Source code available here. |
请发表评论