PDA

View Full Version : [CLOSED] Updating Progress bar from controller



OriCoder
Jan 15, 2015, 12:37 PM
Hi Guys,

I am trying to update a progress bar with the progress of a file download, I get the progress bar up, however it only updates to (say) 7 files of 7 once all the files have been uploaded. As an aside is there a way to change the message, that way I could change the word download to processing

View code:


Html.X().ButtonGroup().MarginSpec("5 5 5 0").Items(
Html.X().Button().Text("Get Trades").ID("GetTrades").Icon(Icon.WorldLink).Width(150)
.DirectEvents(de =>
{
de.Click.Before = "ShowProgressBar()";
de.Click.Url = Url.Action("GetTrades");
}
)
),


Controller:

public ActionResult ShowProgressBar() {
// we're going to want something that lets the user know what is happening....
X.Msg.Show(new MessageBoxConfig
{
Title = "Please wait",
Message = "Connecting Client...",
ProgressText = "Initializing...",
Width = 300,
Progress = true,
Closable = true
});


return this.Direct();
}

public ActionResult GetTrades()
{

// before we do anything lets set up a folder to move the processed files into
// get the date
DateTime now = DateTime.Now;
string datestring = now.ToString("yyyy-MM-dd");
// set the target path (for processed files....)
string targetPath = "//localhost/getFiles/processed/" + datestring +"/";



// create the folder if it doesn't already exist
if (!System.IO.Directory.Exists(targetPath))
{
System.IO.Directory.CreateDirectory(targetPath);
}
// now lets set up the file paths
// set the remote path (Client server)
string remotePath = "/tmp/D:/XXX/XXX/XML/";
// set the local path (downloaded files go here...)
string localPath = "//localhost/getfiles/";

// set a variable to let us know if trades have downloaded
int TradesDownloaded= 0;


// now deal with the files
// open FTP
ftp ftpClient = new ftp(@"ftp://TEST", "TESTUSER", "TESTPASSWORD");
// get the names of each file in the directory
string[] filesForDownload = ftpClient.directoryListSimple(remotePath);
// varable to let us know how many trades are are to be downloaded
int TradesToDownload = (filesForDownload.Length) -3;

//Update message box

X.Msg.UpdateProgress(0, string.Format("Downloading File {0} of {1}...", 0, TradesToDownload));


// loop through files and downlaod
for (int i = 0; i < filesForDownload.Count(); i++) {

//download(remoteFile, localfile)
string remoteFile = remotePath + filesForDownload[i];
string localFile = localPath + filesForDownload[i];
if (ftpClient.download(remoteFile, @localFile)) {
// delete file
ftpClient.delete(remoteFile);
// increment the count
TradesDownloaded++;
X.Msg.UpdateProgress(((int)TradesDownloaded) / TradesToDownload, string.Format("Downloading File {0} of {1}...", TradesDownloaded, TradesToDownload));
}

}
// close the connection
ftpClient = null;
}

fabricio.murta
Jan 15, 2015, 4:41 PM
Hi, can you provide a fully working example so we can try to reproduce your issue here?

You may use something like System.Threading.Thread.Sleep(1000); to simulate download time.

EDIT: I took my time to attempt to build your case.

The issue is that you call a single directMethod for all the files, so the page has no opportunity to update the control.

One approach you can use to update the progress bar correctly is to have two different directMethods and one javascript to fullfill the job:
- One directMethod to get the file list
- Other direct method to, given the file name, download it
- One javascript code to:
- Get the file list from the directMethod
- For each file, call the direct method to download the file and update the progress in every completion, until the file list is completely processed.

I believe this post has very useful information on other approach to attain that: ProgressBar Server Side Update (http://forums.ext.net/showthread.php?15959-CLOSED-ProgressBar-Server-Side-Update)

I really believe this way you can get the behavior you want.

As for the code I've built here to illustrate the problem:

View:


@{
Layout = null;
}

<!DOCTYPE html>

<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>File Upload sample</title>
</head>
<body>
<div>
@Html.X().ResourceManager()
@Html.X().ButtonGroup().MarginSpec("5 5 5 0").Items(
Html.X().Button().Text("Get Trades").ID("GetTradesBtn").Icon(Icon.WorldLink).Width(150)
.DirectEvents(de =>
{ de.Click.Before = "App.direct.ShowProgressBar()"; de.Click.Url = Url.Action("GetTrades"); }
)
)
</div>
</body>
</html>

Controller:
using Ext.Net;
using Ext.Net.MVC;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Web;
using System.Web.Mvc;

namespace ExtNetPlaygroundMCV_v25.Controllers
{
[DirectController]
public class FileUploadController : Controller
{
// GET: FileUpload
public ActionResult Index()
{
return View();
}

[DirectMethod]
public ActionResult ShowProgressBar()
{
// we're going to want something that lets the user know what is happening....
X.Msg.Show(new MessageBoxConfig
{
Title = "Please wait",
Message = "Connecting Client...",
ProgressText = "Initializing...",
Width = 300,
Progress = true,
Closable = true
});


return this.Direct();
}

public ActionResult GetTrades()
{

// before we do anything lets set up a folder to move the processed files into
// get the date
DateTime now = DateTime.Now;
string datestring = now.ToString("yyyy-MM-dd");
// set the target path (for processed files....)
string targetPath = "//localhost/getFiles/processed/" + datestring + "/";

// create the folder if it doesn't already exist
/*
if (!System.IO.Directory.Exists(targetPath))
{
System.IO.Directory.CreateDirectory(targetPath);
}
*/

// now lets set up the file paths
// set the remote path (Client server)
string remotePath = "/tmp/D:/XXX/XXX/XML/";
// set the local path (downloaded files go here...)
string localPath = "//localhost/getfiles/";

// set a variable to let us know if trades have downloaded
int TradesDownloaded = 0;

// now deal with the files
// open FTP
ftp ftpClient = new ftp(@"ftp://TEST", "TESTUSER", "TESTPASSWORD");
// get the names of each file in the directory
string[] filesForDownload = ftpClient.directoryListSimple(remotePath);
// varable to let us know how many trades are are to be downloaded
int TradesToDownload = (filesForDownload.Length);

//Update message box

X.Msg.UpdateProgress(0, string.Format("Downloading File {0} of {1}...", 0, TradesToDownload));


// loop through files and downlaod
for (int i = 0; i < filesForDownload.Count(); i++)
{

//download(remoteFile, localfile)
string remoteFile = remotePath + filesForDownload[i];
string localFile = localPath + filesForDownload[i];
if (ftpClient.download(remoteFile, @localFile))
{
// delete file
ftpClient.delete(remoteFile);
// increment the count
TradesDownloaded++;
X.Msg.UpdateProgress(((int)TradesDownloaded) / TradesToDownload, string.Format("Downloading File {0} of {1}...", TradesDownloaded, TradesToDownload));
}

}
// close the connection
ftpClient = null;

return this.Direct();
}

private void joseph(string remoteFile, string localFile)
{
throw new NotImplementedException();
}
}

public class ftp
{
public ftp(string host, string user, string password)
{

}

public string[] directoryListSimple(string path)
{
return new string[] { "file1.txt", "file2.txt", "file3.txt" };
}

public bool download(string remote, string local)
{
Thread.Sleep(1000);
return true;
}

public void delete(string remote)
{
Thread.Sleep(500);
}
}
}

OriCoder
Jan 16, 2015, 11:54 AM
Thanks this is very helpful, I have split the direct method up as requested, to return the array of files for downloading I have the JS call


var filesForDownload = Ext.net.DirectMethod.request('getGetFilesForDownlo ad', {url: 'ExtNet/getGetFilesForDownload', params:{remotePath: remotePath}});

this does not give me the string array returned by the direct method, how would I go about passing this back to the javascript?

fabricio.murta
Jan 16, 2015, 12:50 PM
You can make either an store (and in codeBehind, you do a store.datasource = list and store.databind()).

Alternatively, an hidden component to store the list of strings.

I'll be shallow in the following simple example, if you need an working one, let me know:



//On the page, you make a
<ext:Label runat="server" ID="fieList" />

//On the directMethod:
fileList.Text = string.Join(filelist,"|"); // for example

//Back on the JavaScript, to get the list "returned" from directMethod, you:
var fileList = App.fileList.text.split("|");


If you are going to have just a few file names and can guarantee they won't have a given separator (like the one I used), I think you are fine with just that.

If you are going to have an arbitrary amount of files, maybe the more complicated store fits you better. You can browse some store examples to understand how to store and load data from JS and code behind but, if you choose a store and is having hard times making it work, let us know. :)

OriCoder
Jan 22, 2015, 12:34 PM
Thanks,

I got it working with a dialog for connecting to server, one for downloading then one for processing, I had to do calls from the JS to the controller for each part with a call to update the progress bar after each stage. An excerpt of the JS code is


Ext.net.DirectMethod.request('ShowDownloadProgress Bar', { url: 'ExtNet/ShowDownloadProgressBar' });

// loop through files and download
for (var i = 2; i < filesForDownload.length; i++) {
if (filesForDownload[i] != "") {
Ext.net.DirectMethod.request('DownloadGetFile', { url: 'ExtNet/DownloadGetFile', params: { remotePath: remotePath, fileForDownload: filesForDownload[i], localPath: localPath, TradesDownloaded: TradesToDownload - 3 + i, TradesToDownload: TradesToDownload} });
// increment the count
TradesDownloaded++;
}
Ext.net.DirectMethod.request('RefreshDownloadProgr ess', { url: 'ExtNet/RefreshDownloadProgress', params: { TradesDownloaded: TradesDownloaded, TradesToDownload: TradesToDownload} });
}

It took a while to get everything working and talking to each other, if anyone wants more of the code I can supply but the snippet above gives a general idea.


Thanks again Avenger!

fabricio.murta
Jan 22, 2015, 1:22 PM
I'm thrilled to hear success from you! Thanks for sharing the outcome!