Introduction
Silverlight applications have no direct access to the file system of server. To gain access to the server file system needs to be done the proxy (gateway) page.
I created a gateway class for processing requests. The class can be used in the ASP .NET WebForm and ASP.NET MVC projects.
File Manager is created as custom control based on the ListBox
. The control has a method for sending requests to the server.
All requests are sent asynchronously via helper class. The helper class is optimized for File Manager, but it can be easily modified for other purposes.
Data exchange is carried out in the JSON. Is it optimal for traffic volume.
Server
Gateway
class for processing requests created on the Class Library project.
The class has a main method - GetResult
. The method for processing requests returns a JSON string
.
Requests data are taken from HttpContext.Current.Request
class. For it, I created a helper variable - Request
, and also Server
.
HttpRequest Request = HttpContext.Current.Request;
HttpServerUtility Server = HttpContext.Current.Server;
Server can only handle POST
requests. Request parameters are available in the Form
collection.
Server will handle the six operations:
check
- check file name
upload
- upload and save file on the server
newdir
- create a new directory
delete
- delete file or directory
rename
- change name of the file or directory
get
(default) - get file and directories list
Name of the operation will be contained in the parameter cmd
.
string cmd = "";
if (!String.IsNullOrEmpty(Request.Form["cmd"])) { cmd = Request.Form["cmd"].ToLower(); }
The root directory name contains a _Root
variable. The client must pass a relative path on the path
field.
string _Root = ""; string path = "";
if (!String.IsNullOrEmpty(Request.Form["path"]))
{ path = Request.Form["path"]; } else { path = "/"; }
if (!path.EndsWith("/")) path += "/";
Before executing the operation (cmd), the server must verify the existence of a directory.
DirectoryInfo DI = new DirectoryInfo
(Server.MapPath(String.Format("~/{0}{1}", _Root, path)));
if (!DI.Exists)
{
result = GetError(String.Format("Error. The directory \"{0}\" not found.",
String.Format("~/{0}{1}", _Root, path)));
return result.ToString();
}
I did not create verification of the user authorization and access, but you can create it.
Server returns JSON string. I created two helper functions for it. First - GetError
return JSON object with error message. Second - GetJsonString
converting object to JSON.
private StringBuilder GetError(string msg)
{
return GetJsonString(new { stat = "err", msg = msg });
}
private StringBuilder GetJsonString(object source)
{
StringBuilder result = new StringBuilder();
JavaScriptSerializer myJSON = new JavaScriptSerializer();
myJSON.Serialize(source, result);
return result;
}
I used anonymous types with next properties:
stat
- server response code: ok - ok, err - error
msg
- error message, if stat = err
allowUp
- has top-level directory (only for file list requests)
data
- array of files and directories (only for file list requests):
name
- file or directory name
size
- file size (only for files)
type
- item type: 0 - directory, 1 - file
url
- file URL
public class Gateway
{
private string _Root = "Custom";
public Gateway() { }
public string GetResult()
{
if (HttpContext.Current == null) throw new Exception("HTTP request is required.");
HttpRequest Request = HttpContext.Current.Request;
HttpServerUtility Server = HttpContext.Current.Server;
StringBuilder result = new StringBuilder();
try
{
string cmd = "", path = "";
if (!String.IsNullOrEmpty(Request.Form["cmd"]))
{ cmd = Request.Form["cmd"].ToLower(); }
if (!String.IsNullOrEmpty(Request.Form["path"]))
{ path = Request.Form["path"]; } else { path = "/"; }
if (!path.EndsWith("/")) path += "/";
DirectoryInfo DI = new DirectoryInfo
(Server.MapPath(String.Format("~/{0}{1}", _Root, path)));
if (!DI.Exists)
{
result = GetError(String.Format("Error.
The directory \"{0}\" not found.", String.Format("~/{0}{1}", _Root, path)));
return result.ToString();
}
if (cmd == "check")
{
#region check file name
if (File.Exists(Path.Combine(DI.FullName, Request.Form["name"])))
{
result = GetJsonString(new { stat = "err", msg = String.Format
("Sorry, file \"{0}\" is exists on the directory
\"{1}\".", Request.Form["name"], path) });
}
else
{
result = GetJsonString(new { stat = "ok" });
}
#endregion
}
else if (cmd == "upload")
{
#region save file
if (Request.Files["file1"] == null || Request.Files["file1"].ContentLength <= 0)
{
result = GetError("Error. File is required.");
}
else
{
if (File.Exists(Path.Combine(DI.FullName, Request.Files["file1"].FileName)))
{
result = GetJsonString(new { stat = "err", msg = String.Format
("Sorry, file \"{0}\" is exists on the directory \"{1}\".",
Request.Files["file1"].FileName, path) });
}
else
{
using (FileStream fs = System.IO.File.Create
(Path.Combine(DI.FullName, Request.Files["file1"].FileName)))
{
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = Request.Files["file1"].
InputStream.Read(buffer, 0, buffer.Length)) != 0)
{
fs.Write(buffer, 0, bytesRead);
}
}
result = GetJsonString(new { stat = "ok" });
}
}
#endregion
}
else if (cmd == "newdir")
{
#region create a new directory
if (String.IsNullOrEmpty(Request.Form["name"]))
{
result = GetError("Error. Directory name is required.");
}
else
{
DirectoryInfo d = new DirectoryInfo(Path.Combine
(DI.FullName, Request.Form["name"]));
if (d.Exists)
{
result = GetError("Sorry, directory is exists.");
}
else
{
d.Create();
result = GetJsonString(new { stat = "ok" });
}
}
#endregion
}
else if (cmd == "delete")
{
#region delete file/directory
if (String.IsNullOrEmpty(Request.Form["name"]))
{
result = GetError("Error. Name is required.");
}
else
{
if (File.GetAttributes(Path.Combine(DI.FullName,
Request.Form["name"])) == FileAttributes.Directory)
{
Directory.Delete(Path.Combine(DI.FullName, Request.Form["name"]), true);
}
else
{
File.Delete(Path.Combine(DI.FullName, Request.Form["name"]));
}
result = GetJsonString(new { stat = "ok" });
}
#endregion
}
else if (cmd == "rename")
{
#region rename file/directory
string oldName = Request.Form["oldName"], newName = Request.Form["newName"];
if (String.IsNullOrEmpty(oldName) || String.IsNullOrEmpty(newName))
{
result = GetError("Error. Name is required.");
}
else
{
if (newName != oldName)
{
if (File.GetAttributes(Path.Combine(DI.FullName,
oldName)) == FileAttributes.Directory)
{
Directory.Move(Path.Combine(DI.FullName, oldName),
Path.Combine(DI.FullName, newName));
}
else
{
File.Move(Path.Combine(DI.FullName, oldName),
Path.Combine(DI.FullName, newName));
}
}
result = GetJsonString(new { stat = "ok" });
}
#endregion
}
else
{
#region file list
ArrayList files = new ArrayList();
foreach (DirectoryInfo d in DI.GetDirectories())
{
files.Add(new
{
name = d.Name,
size = 0,
type = 0, url = String.Format("http://{0}/{1}{2}{3}", Request.Url.Host +
(Request.Url.Port > 80 ? ":" + Request.Url.Port.ToString() : ""),
_Root, path, d.Name)
});
}
foreach (FileInfo f in DI.GetFiles())
{
files.Add(new
{
name = f.Name,
size = f.Length,
type = 1, url = String.Format("http://{0}/{1}{2}{3}", Request.Url.Host +
(Request.Url.Port > 80 ? ":" + Request.Url.Port.ToString() : ""),
_Root, path, f.Name)
});
}
bool allowUp = !String.IsNullOrEmpty(path.Trim("/".ToCharArray()));
result = GetJsonString(new { stat = "ok", allowUp = allowUp, data = files });
#endregion
}
}
catch (Exception ex)
{
result = GetError(ex.Message);
}
return result.ToString();
}
private StringBuilder GetError(string msg)
{
return GetJsonString(new { stat = "err", msg = msg });
}
private StringBuilder GetJsonString(object source)
{
StringBuilder result = new StringBuilder();
JavaScriptSerializer myJSON = new JavaScriptSerializer();
myJSON.Serialize(source, result);
return result;
}
}
The Gateway
class is easy to use ASP. NET WebForms. For example, in the ASP .NET Handler (Gateway.ashx).
public class Gateway : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
Nemiro.FileManager.Common.Gateway myGateway =
new Nemiro.FileManager.Common.Gateway();
context.Response.ContentType = "application/json";
context.Response.Write(myGateway.GetResult());
}
public bool IsReusable
{
get
{
return false;
}
}
}
And also in the ASP .NET MVC. For example, to the Gateway
Action in HomeController
.
public class HomeController : Controller
{
[HttpPost]
public ActionResult Gateway()
{
Nemiro.FileManager.Common.Gateway myGateway =
new Nemiro.FileManager.Common.Gateway();
return new ContentResult() { Content = myGateway.GetResult(),
ContentType = "application/json", ContentEncoding = System.Text.Encoding.UTF8 };
}
}
Silveright (client)
WebHelper Class
The WebHelper
class implements the ability to send asynchronous HTTP requests.
For request parameters, I created two additional classes.
First - the QueryItem
class for parameter data. The QueryItem
class can contain text data and files. Second - the QueryItemCollection
collections of QueryItem
.
The WebHelper
class has a one public
method - Execute
. The method takes a reference to a callback function.
For callback function, I created delegate.
public delegate void WebCallback(string stat, string msg, bool allowUp,
JsonValue data, object tag);
As you can see, to the callback function will be transferred server response from JSON. It is special for File Manager, but you can change delegate and callback function, it is easy.
public class WebHelper
{
public delegate void WebCallback
(string stat, string msg, bool allowUp, JsonValue data, object tag);
private string _Method = "POST";
private QueryItemCollection _Queries = new QueryItemCollection();
private string _Url = String.Empty;
private string _Boundary = String.Empty;
private WebCallback _Callback = null;
public string Method
{
get
{
return _Method;
}
set
{
_Method = value;
if (String.IsNullOrEmpty(_Method) || _Method.ToUpper() != "GET" ||
_Method.ToUpper() != "POST") _Method = "POST";
}
}
public QueryItemCollection Queries
{
get
{
return _Queries;
}
set
{
_Queries = value;
}
}
public string Url
{
get
{
return _Url;
}
set
{
_Url = value;
}
}
public object Tag { get; set; }
public WebHelper(string url) : this (url, "POST") { }
public WebHelper(string url, string method)
{
this.Url = url;
this.Method = method;
}
public void Execute(WebCallback callback)
{
if (String.IsNullOrEmpty(_Url))
{
return;
}
_Callback = callback;
string url = _Url;
#region add parameters to url for GET requests
if (_Method == "GET")
{
string qs = _Queries.GetQueryString();
if (url.EndsWith("?"))
{
url += "&" + qs;
}
else
{
url += "?" + qs;
}
}
#endregion
HttpWebRequest myReq = (HttpWebRequest)HttpWebRequest.Create(_Url);
myReq.Method = _Method;
#region Content-Type for POST requests
if (_Method == "POST")
{
if (_Queries.HasFiles())
{
_Boundary = "----------" + DateTime.Now.Ticks.ToString("x"); myReq.ContentType = "multipart/form-data; boundary=" + _Boundary;
}
else
{
myReq.ContentType = "application/x-www-form-urlencoded";
}
}
#endregion
myReq.BeginGetRequestStream(Execute_BeginGetRequestStream, myReq);
}
private void Execute_BeginGetRequestStream(IAsyncResult result)
{
HttpWebRequest r = result.AsyncState as HttpWebRequest;
#region write parameters to request (only for POST)
if (_Queries.Count > 0 && _Method == "POST")
{
Stream myStream = r.EndGetRequestStream(result);
if (String.IsNullOrEmpty(_Boundary))
{
byte[] buffer = Encoding.UTF8.GetBytes(_Queries.GetQueryString());
myStream.Write(buffer, 0, buffer.Length);
}
else
{
byte[] buffer = null;
foreach (QueryItem itm in _Queries)
{
if (!itm.IsFile)
{
string q = String.Format("\r\n--{0}\r\nContent-Disposition:
form-data; name=\"{1}\";\r\n\r\n{2}",
_Boundary, itm.Name, itm.ValueAsString());
buffer = Encoding.UTF8.GetBytes(q);
myStream.Write(buffer, 0, buffer.Length);
}
else
{
string q = String.Format("\r\n--{0}\r\nContent-Disposition:
form-data; name=\"{1}\"; filename=\"{2}\"\r\nContent-Type: {3}\r\n\r\n",
_Boundary, itm.Name, itm.FileName, itm.GetContentType());
buffer = Encoding.UTF8.GetBytes(q);
myStream.Write(buffer, 0, buffer.Length);
buffer = new byte[4096]; int bytesRead = 0; int totalSize = 0;
while ((bytesRead = ((Stream)itm.Value).Read
(buffer, 0, buffer.Length)) != 0) {
myStream.Write(buffer, 0, buffer.Length); totalSize += bytesRead;
}
}
}
buffer = Encoding.UTF8.GetBytes(String.Format("\r\n--{0}--\r\n", _Boundary));
myStream.Write(buffer, 0, buffer.Length);
}
myStream.Close();
}
#endregion
r.BeginGetResponse(Execute_Complete, r);
}
private void Execute_Complete(IAsyncResult result)
{
HttpWebRequest myReq = (HttpWebRequest)result.AsyncState;
HttpWebResponse myResp = (HttpWebResponse)myReq.EndGetResponse(result);
string stat = "", msg = "";
bool allowUp = false;
JsonValue data = null;
if (myResp.StatusCode == HttpStatusCode.OK) {
StreamReader reader = new StreamReader(myResp.GetResponseStream(), Encoding.UTF8);
string page = reader.ReadToEnd();
JsonValue json = System.Json.JsonObject.Parse(page);
if (json.ContainsKey("stat")) stat = json["stat"];
if (json.ContainsKey("msg")) msg = json["msg"];
if (json.ContainsKey("allowUp")) allowUp = json["allowUp"];
if (json.ContainsKey("data")) data = json["data"];
}
else
{
stat = "err";
msg = String.Format("Server error {0}", myResp.StatusCode);
}
if (_Callback != null)
{
_Callback(stat, msg, allowUp, data, this.Tag);
}
}
#region additional classes
public class QueryItemCollection : List<QueryItem>
{
public void Add(string name, string value)
{
this.Add(new QueryItem(name, value));
}
public void Add(string name, string fileName, Stream stream)
{
this.Add(new QueryItem(name, fileName, stream));
}
public string GetQueryString()
{
string qs = "";
foreach (QueryItem itm in this)
{
if (!String.IsNullOrEmpty(qs)) qs += "&";
qs += String.Format("{0}={1}", itm.Name, itm.ValueForUrl());
}
return qs;
}
public bool HasFiles()
{
foreach (QueryItem itm in this)
{
if (itm.IsFile) return true;
}
return false;
}
}
public class QueryItem
{
public string Name { get; set; }
public object Value{get;set;}
public string FileName { get; set; }
public bool IsFile
{
get
{
return this.Value != null && this.Value.GetType() == typeof(FileStream);
}
}
public QueryItem(string name, string value)
{
this.Name = name;
this.Value = value;
}
public QueryItem(string name, string fileName, Stream stream)
{
this.Name = name;
this.FileName = fileName;
this.Value = stream;
}
public string ValueForUrl()
{
return HttpUtility.UrlEncode(this.Value.ToString());
}
public string ValueAsString()
{
return this.Value.ToString();
}
public string GetContentType()
{ return "application/data";
}
}
#endregion
}
FileList Control
The FileList
control inherited from ListBox
. Each item will also be custom.
FileItem
The FileItem
class inherited from StackPanel
. The Item will contain an icon, name, file size and 3 buttons for open, rename and delete item. But the class cannot independently send requests to server. This is only possible via FileList
(Parent
).
public class FileItem : StackPanel
{
public int ItemType { get; set; }
public string FileName { get; set; }
public double FileSize { get; set; }
public string FileUrl { get; set; }
public bool IsEdit { get; set; }
public bool CanEdit { get; set; }
private string _NewName = "";
public string NewName
{
get
{
return _NewName;
}
}
private int _ItemIndex = 0;
public FileItem(int type, string name, string url, double size)
{
this.ItemType = type;
this.FileName = name;
this.FileUrl = url;
this.FileSize = size;
this.CanEdit = type != -1;
this.Orientation = Orientation.Horizontal;
Image myImg = new Image() { Width = 16, Height = 16 };
if (type == -1)
{
myImg.Source = new System.Windows.Media.Imaging.BitmapImage
(new Uri("Images/folder2.png", UriKind.Relative));
}
else if (type == 0)
{
myImg.Source = new System.Windows.Media.Imaging.BitmapImage
(new Uri("Images/folder.png", UriKind.Relative));
}
else
{
string fileExtension = System.IO.Path.GetExtension(name).ToLower();
string[] fileType = { ".exe", ".bat", ".cmd", ".asp", ".aspx", ".html",
".htm", ".cs", ".txt", ".doc", ".docx", ".php", ".gif", ".png", ".jpg",
".jpeg", ".bmp", ".js", ".xls", "xlsx", ".zip" };
string[] fileIcon = { "exe.png", "cmd.png", "cmd.png", "aspx.png", "aspx.png",
"html.png", "html.png", "csharp.png", "txt.png", "doc.png", "doc.png", "php.png",
"image.png", "image.png", "image.png", "image.png", "bmp.png",
"script.png", "xls.png", "xls.png", "zip.png" };
int idx = Array.IndexOf(fileType, fileExtension);
if (idx != -1)
{
myImg.Source = new System.Windows.Media.Imaging.BitmapImage
(new Uri("Images/" + fileIcon[idx], UriKind.Relative));
}
else
{
myImg.Source = new System.Windows.Media.Imaging.BitmapImage
(new Uri("Images/unknown.png", UriKind.Relative));
}
}
myImg.Margin = new Thickness(2, 0, 0, 0);
this.Children.Add(myImg);
this.Children.Add(new TextBlock()
{ Text = name, Margin = new Thickness(2, 0, 0, 0) });
Image myImg2 = new Image() { Width = 9, Height = 9, Cursor = Cursors.Hand };
myImg2.Margin = new Thickness(4, 0, 0, 0);
myImg2.Source = new System.Windows.Media.Imaging.BitmapImage
(new Uri("Images/open.png", UriKind.Relative));
myImg2.MouseLeftButtonUp += (sender, e) =>
{
Open();
};
this.Children.Add(myImg2);
if (type != -1)
{
Image myImg4 = new Image() { Width = 9, Height = 9, Cursor = Cursors.Hand };
myImg4.Margin = new Thickness(4, 0, 0, 0);
myImg4.Source = new System.Windows.Media.Imaging.BitmapImage
(new Uri("Images/edit.png", UriKind.Relative));
myImg4.MouseLeftButtonUp += (sender, e) =>
{
EditStart();
};
this.Children.Add(myImg4);
Image myImg3 = new Image() { Width = 9, Height = 9, Cursor = Cursors.Hand };
myImg3.Margin = new Thickness(4, 0, 0, 0);
myImg3.Source = new System.Windows.Media.Imaging.BitmapImage
(new Uri("Images/del.png", UriKind.Relative));
myImg3.MouseLeftButtonUp += (sender, e) =>
{
Delete();
};
this.Children.Add(myImg3);
}
if (type == 1) {
this.Children.Add(new TextBlock() { Text = String.Format
("{0:##,###,##0.00} Kb", size), HorizontalAlignment =
System.Windows.HorizontalAlignment.Right, Margin = new Thickness(8, 0, 0, 0),
FontSize = 9, Foreground =
new SolidColorBrush(Color.FromArgb(255, 128, 128, 128)) });
}
this.MouseLeftButtonUp += new MouseButtonEventHandler(FileItem_MouseLeftButtonUp);
}
private DateTime _lastClick = DateTime.Now;
private bool _firstClickDone = false;
private void FileItem_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
DateTime clickTime = DateTime.Now;
TimeSpan span = clickTime - _lastClick;
if (span.TotalMilliseconds > 350 || !_firstClickDone) {
_firstClickDone = true;
_lastClick = clickTime;
}
else
{
_firstClickDone = false;
Open();
}
}
public void EditStart()
{
if (this.IsEdit) return;
this.Children.RemoveAt(1);
this.Children.Insert(1, new TextBox()
{ Text = this.FileName, Margin = new Thickness(2, 0, 0, 0) });
((TextBox)this.Children[1]).LostFocus +=
new RoutedEventHandler(EditTextBox_LostFocus);
if (this.ItemType == 0)
{
((TextBox)this.Children[1]).SelectAll();
}
else
{
((TextBox)this.Children[1]).SelectionStart = 0;
((TextBox)this.Children[1]).SelectionLength = this.FileName.LastIndexOf(".");
}
_ItemIndex = ((FileList)this.Parent).SelectedIndex;
((TextBox)this.Children[1]).Focus();
this.IsEdit = true;
}
private void EditTextBox_LostFocus(object sender, RoutedEventArgs e)
{
EditComplete();
}
public void EditCancel()
{
this.Children.RemoveAt(1);
this.Children.Insert(1, new TextBlock()
{ Text = this.FileName, Margin = new Thickness(2, 0, 0, 0) });
this.IsEdit = false;
((FileList)this.Parent).Focus();
}
public void EditComplete()
{
((TextBox)this.Children[1]).LostFocus -= EditTextBox_LostFocus;
_NewName = ((TextBox)this.Children[1]).Text;
((FileList)this.Parent).SetNewName(this);
}
public void Open()
{
if (this.ItemType == 1)
{
HtmlPage.PopupWindow(new Uri(this.FileUrl), "_blank", null);
}
else if (this.ItemType == 0)
{
if (!((FileList)this.Parent).Path.EndsWith("/"))
((FileList)this.Parent).Path += "/";
((FileList)this.Parent).Path += this.FileName;
((FileList)this.Parent).UpdateFileList();
}
else if (this.ItemType == -1)
{
string[] arr = ((FileList)this.Parent).Path .Split("/".ToCharArray());
Array.Resize(ref arr, arr.Length - 1);
((FileList)this.Parent).Path = String.Join("/", arr);
((FileList)this.Parent).UpdateFileList();
}
}
public void Delete()
{
if (this.ItemType == 0)
{
if (MessageBox.Show(String.Format("Are you want delete the directory
\"{0}\"?", this.FileName), "Delete",
MessageBoxButton.OKCancel) == MessageBoxResult.OK)
{
((FileList)this.Parent).DeleteItem(this);
}
}
else if (this.ItemType == 1)
{
if (MessageBox.Show(String.Format("Are you want delete the file
\"{0}\"?", this.FileName), "Delete",
MessageBoxButton.OKCancel) == MessageBoxResult.OK)
{
((FileList)this.Parent).DeleteItem(this);
}
}
}
}
FileList
The FileList
contains a helper method for showing errors via standard MessageBox
. Because the requests are executed in separate threads, MessageBox
can be called only from the main thread via BeginInvoke
.
private void ShowError(string msg)
{
this.Dispatcher.BeginInvoke(() =>
{
MessageBox.Show(msg, "Error", MessageBoxButton.OK);
});
}
To implement the ProgressBar
, the class contain two events: Process
and Complete
.
public event EventHandler Process;
public event EventHandler Complete;
ProgressBar
will not be to the FileList
, is it external (to page). For progress, I created child windows.
private string _Url = "http://localhost:58646/Gateway.ashx"; private PleaseWait myPleaseWait = null;
public MainPage()
{
InitializeComponent();
fileList1.Url = _Url;
fileList1.Process += new EventHandler(fileList1_Process);
fileList1.Complete += new EventHandler(fileList1_Complete);
}
private void fileList1_Process(object sender, EventArgs e)
{
this.Dispatcher.BeginInvoke(() =>
{
if (myPleaseWait != null &&
myPleaseWait.Visibility == System.Windows.Visibility.Visible) return;
myPleaseWait = new PleaseWait();
myPleaseWait.Show();
});
}
private void fileList1_Complete(object sender, EventArgs e)
{
this.Dispatcher.BeginInvoke(() =>
{
if (myPleaseWait != null)
{
myPleaseWait.Close();
myPleaseWait = null;
}
tbPath.Text = fileList1.Path;
});
}
For upload files, I created helper class UploadItem
because sending is done in two stages:
- check
- upload
public class UploadItem
{
public event EventHandler Complete;
public enum StateList
{
OK,
Error,
Wait
}
private StateList _State = StateList.Wait;
private string _Message = String.Empty;
private int _Index = 0;
private string _FileName = String.Empty;
private Stream _FileStream = null;
private string _Path = String.Empty;
private string _Url = String.Empty;
public StateList State
{
get { return _State; }
}
public string Message
{
get { return _Message; }
}
public string FileName
{
get { return _FileName; }
}
public int Index
{
get { return _Index; }
}
public UploadItem(int idx, FileInfo f, string url, string path)
{
_Index = idx;
_Path = path;
_Url = url;
_FileName = f.Name; _FileStream = f.OpenRead(); }
public void Run()
{
try
{
WebHelper w = new WebHelper(_Url);
w.Queries.Add("cmd", "check");
w.Queries.Add("path", _Path);
w.Queries.Add("name", _FileName);
w.Execute(CheckNameResult);
}
catch (Exception ex)
{
_State = StateList.Error;
_Message = ex.Message;
if(Complete != null) Complete(this, null);
}
}
private void CheckNameResult(string stat, string msg,
bool allowUp, JsonValue data, object tag)
{
try
{
if (stat == "ok")
{
WebHelper w = new WebHelper(_Url);
w.Queries.Add("cmd", "upload");
w.Queries.Add("path", _Path);
w.Queries.Add("file1", _FileName, _FileStream); w.Execute(UploadResult);
}
else
{
_State = StateList.Error;
_Message = msg;
if(Complete != null) Complete(this, null);
}
}
catch (Exception ex)
{
_State = StateList.Error;
_Message = ex.Message;
if(Complete != null) Complete(this, null);
}
}
private void UploadResult(string stat, string msg, bool allowUp,
JsonValue data, object tag)
{
if (stat == "ok")
{
_State = StateList.OK;
}
else
{
_State = StateList.Error;
_Message = msg;
}
if(Complete != null) Complete(this, null);
}
}
The FileList
control has a UploadList
collection.
private List<UploadItem> _UploadFiles = null;
And method for adding UploadItem
to collection.
public void AddUploadItem(FileInfo f)
{
if (_UploadFiles == null) _UploadFiles = new List<uploaditem />();
UploadItem itm = new UploadItem(_UploadFiles.Count, f, this.Url, this.Path);
itm.Complete += new EventHandler(UploadItem_Complete);
_UploadFiles.Add(itm);
}
The FileList
can take files via Drag and Drop.
this.Drop += new DragEventHandler(FileList_Drop);
private void FileList_Drop(object sender, DragEventArgs e)
{
FileInfo[] files = e.Data.GetData(DataFormats.FileDrop) as FileInfo[];
foreach (FileInfo f in files)
{
this.AddUploadItem(f);
}
this.Upload();
}
Uploading files starting on the Upload
method each from _UploadList
.
public void Upload()
{
if (_UploadFiles == null || _UploadFiles.Count <= 0) return;
_UploadErrorMessages = new StringBuilder();
if (Process!=null) Process(this, null);;
foreach (UploadItem itm in _UploadFiles)
{
itm.Run(); }
}
After sending the file to the server, it is removed from _UploadList
on the UploadItem_Complete
handler. When the files over, FileList
update the list of files from server.
private void UploadItem_Complete(object sender, EventArgs e)
{
this.Dispatcher.BeginInvoke(() =>
{
UploadItem itm = sender as UploadItem;
if (itm.State == UploadItem.StateList.Error)
{
_UploadErrorMessages.AppendLine(itm.Message);
}
_UploadFiles.Remove(itm);
if (_UploadFiles.Count == 0)
{
if (Complete != null) Complete(this, null);
if (_UploadErrorMessages.Length <= 0)
{
UpdateFileList();
}
else
{
ShowError(_UploadErrorMessages.ToString());
}
}
});
}
The entire code of the FileList
class.
public class FileList : ListBox
{
public event EventHandler Process;
public event EventHandler Complete;
private string _Url = "";
private string _Path = "/";
private List<UploadItem> _UploadFiles = null; private StringBuilder _UploadErrorMessages = null;
public string Path
{
get
{
return _Path;
}
set
{
_Path = value;
if (String.IsNullOrEmpty(_Path)) _Path = "/";
}
}
public List<UploadItem> UploadFiles
{
get
{
return _UploadFiles;
}
}
public string Url
{
get
{
return _Url;
}
set
{
_Url = value;
if (!System.ComponentModel.DesignerProperties.IsInDesignTool) { UpdateFileList();
}
}
}
public FileList()
{
ImageBrush ib = new ImageBrush();
ib.ImageSource = new System.Windows.Media.Imaging.BitmapImage
(new Uri("Images/2.png", UriKind.Relative));
ib.Stretch = Stretch.Fill;
this.Background = ib;
this.AllowDrop = true;
this.KeyUp += new KeyEventHandler(FileList_KeyUp); this.Drop += new DragEventHandler(FileList_Drop); }
private void FileList_KeyUp(object sender, KeyEventArgs e)
{
if (((FileList)sender).SelectedItem == null) return;
FileItem itm = ((FileList)sender).SelectedItem as FileItem;
if (e.Key == Key.Enter && !itm.IsEdit)
{ itm.Open();
}
else if (e.Key == Key.Enter && itm.IsEdit)
{ itm.EditComplete();
}
else if (e.Key == Key.F2 && itm.CanEdit && !itm.IsEdit)
{ itm.EditStart();
}
else if (e.Key == Key.Escape && itm.IsEdit)
{ itm.EditCancel();
}
else if (e.Key == Key.Delete && !itm.IsEdit)
{ itm.Delete();
}
else if (e.Key == Key.F5)
{ UpdateFileList();
}
}
#region update file list
public void UpdateFileList()
{
if (Process!=null) Process(this, null);;
WebHelper w = new WebHelper(this.Url);
w.Queries.Add("cmd", "get");
w.Queries.Add("path", _Path);
w.Execute(UpdateFileListResult); }
private void UpdateFileListResult
(string stat, string msg, bool allowUp, JsonValue data, object tag)
{
if (stat == "ok")
{
this.Dispatcher.BeginInvoke(() =>
{
this.Items.Clear();
});
if (allowUp)
{
AddItem(-1, "...", "", 0);
}
if (data != null && data.Count > 0)
{
foreach (JsonValue itm in data)
{
AddItem(itm["type"], itm["name"], itm["url"], itm["size"]);
}
}
this.Dispatcher.BeginInvoke(() =>
{
this.SelectedIndex = -1;
this.Focus();
if (this.Items.Count > 0) this.SelectedIndex = 0;
});
}
else
{
ShowError("Error. " + msg);
}
if (Complete != null) Complete(this, null); }
private void AddItem(int type, string name, string url, double size)
{
this.Dispatcher.BeginInvoke(() =>
{
FileItem itm = new FileItem(type, name, url, size);
this.Items.Add(itm);
});
}
#endregion
#region rename file or directory
public void SetNewName(FileItem itm)
{
if (itm == null || !itm.IsEdit)
{
MessageBox.Show("The item can not be changed!", "Error", MessageBoxButton.OK);
return;
}
if (Process!=null) Process(this, null);
WebHelper w = new WebHelper(this.Url);
w.Queries.Add("cmd", "rename");
w.Queries.Add("path", _Path);
w.Queries.Add("oldName", itm.FileName);
w.Queries.Add("newName", itm.NewName);
w.Tag = itm; w.Execute(SetNewNameResult);
}
private void SetNewNameResult(string stat, string msg,
bool allowUp, JsonValue data, object tag)
{
if (stat == "ok")
{
this.Dispatcher.BeginInvoke(() =>
{
FileItem itm = tag as FileItem;
itm.FileName = itm.NewName;
itm.FileUrl = itm.FileUrl.Substring
(0, itm.FileUrl.LastIndexOf("/") + 1) + itm.FileName;
itm.EditCancel(); });
}
else
{
ShowError("Error. " + msg);
}
if (Complete != null) Complete(this, null);
}
#endregion
#region delete file or directory
public void DeleteItem(FileItem itm)
{
if (Process!=null) Process(this, null);
WebHelper w = new WebHelper(this.Url);
w.Queries.Add("cmd", "delete");
w.Queries.Add("path", _Path);
w.Queries.Add("name", itm.FileName);
w.Tag = itm; w.Execute(DeleteItemResult);
}
private void DeleteItemResult
(string stat, string msg, bool allowUp, JsonValue data, object tag)
{
if (stat == "ok")
{
this.Dispatcher.BeginInvoke(() =>
{
FileItem itm = tag as FileItem;
this.Items.Remove(itm);
});
}
else
{
ShowError("Error. " + msg);
}
if (Complete != null) Complete(this, null);
}
#endregion
#region create new directory
public void CreateDirectory(string name)
{
if (Process!=null) Process(this, null);
WebHelper w = new WebHelper(this.Url);
w.Queries.Add("cmd", "newdir");
w.Queries.Add("path", _Path);
w.Queries.Add("name", name);
w.Execute(CreateDirectoryResult);
}
private void CreateDirectoryResult
(string stat, string msg, bool allowUp, JsonValue data, object tag)
{
if (Complete != null) Complete(this, null);
if (stat == "ok")
{
UpdateFileList();
}
else
{
ShowError("Error. " + msg);
}
}
#endregion
#region upload file
public void AddUploadItem(FileInfo f)
{
if (_UploadFiles == null) _UploadFiles = new List<UploadItem>();
UploadItem itm = new UploadItem(_UploadFiles.Count, f, this.Url, this.Path);
itm.Complete += new EventHandler(UploadItem_Complete);
_UploadFiles.Add(itm);
}
public void Upload()
{
if (_UploadFiles == null || _UploadFiles.Count <= 0) return;
_UploadErrorMessages = new StringBuilder();
if (Process!=null) Process(this, null);;
foreach (UploadItem itm in _UploadFiles)
{
itm.Run(); }
}
private void UploadItem_Complete(object sender, EventArgs e)
{
this.Dispatcher.BeginInvoke(() =>
{
UploadItem itm = sender as UploadItem;
if (itm.State == UploadItem.StateList.Error)
{
_UploadErrorMessages.AppendLine(itm.Message);
}
_UploadFiles.Remove(itm);
if (_UploadFiles.Count == 0)
{
if (Complete != null) Complete(this, null);
if (_UploadErrorMessages.Length <= 0)
{
UpdateFileList();
}
else
{
ShowError(_UploadErrorMessages.ToString());
}
}
});
}
private void FileList_Drop(object sender, DragEventArgs e)
{
FileInfo[] files = e.Data.GetData(DataFormats.FileDrop) as FileInfo[];
foreach (FileInfo f in files)
{
this.AddUploadItem(f);
}
this.Upload();
}
#endregion
private void ShowError(string msg)
{
this.Dispatcher.BeginInvoke(() =>
{
MessageBox.Show(msg, "Error", MessageBoxButton.OK);
});
}
}
Using the code
Main files of FileList
control: FileList.cs, FileItem.cs, WebHelper.cs and UploadItem.cs (FileManage
project). For server - Gateway.cs (FileManager.Common
project).
Add FileList
to Silverlight page.
<my:FileList Height="256" HorizontalAlignment="Left"
Margin="12,41,0,0" x:Name="fileList1" VerticalAlignment="Top"
Width="573" Grid.ColumnSpan="2" Grid.RowSpan="2" />
Add the Gateway code to ASP .NET handler (ashx for WebForms) or action (for MVC) and run the server.
FileManager.Common.Gateway myGateway = new FileManager.Common.Gateway();
context.Response.ContentType = "application/json";
context.Response.Write(myGateway.GetResult());
Set Url
property for FileList
to the Gateway server page.
public MainPage()
{
InitializeComponent();
fileList1.Url = "http://localhost:58646/Gateway.ashx"; }
Enjoy!