Click here to Skip to main content
Click here to Skip to main content

Silverlight File Manager

, 8 Jan 2012 CPL
Rate this:
Please Sign up or sign in to vote.
The Silverlight File Manager on the ListBox control based universal server handler may be working on the ASP .NET WebForms and MVC projects. All requests are sent asynchronously via helper class.
Silverlight File Manager

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 = ""; // empty - server root directory
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"; // root directory

  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
    {
      // ...
      // here you can make authorization
      // ..

      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
        {
          // check file name
          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
          { 
            // save
            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
        {
          // check name
          DirectoryInfo d = new DirectoryInfo(Path.Combine
		(DI.FullName, Request.Form["name"]));
          if (d.Exists)
          {
            result = GetError("Sorry, directory is exists.");
          }
          else
          {
            // create directory
            d.Create();
            // is ok
            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)
          {
            // is directory, 
            Directory.Delete(Path.Combine(DI.FullName, Request.Form["name"]), true);
          }
          else
          {
            // is file
            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)
            {
              // rename directory
              Directory.Move(Path.Combine(DI.FullName, oldName), 
			Path.Combine(DI.FullName, newName));
            }
            else
            {
              // rename file
              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();
        // dicrectories
        foreach (DirectoryInfo d in DI.GetDirectories())
        {
          files.Add(new
          {
            name = d.Name,
            size = 0,
            type = 0, // type = 0 - is directory
            url = String.Format("http://{0}/{1}{2}{3}", Request.Url.Host + 
            (Request.Url.Port > 80 ? ":" + Request.Url.Port.ToString() : ""), 
            _Root, path, d.Name) 
          }); 
        }
        // files
        foreach (FileInfo f in DI.GetFiles())
        {
          files.Add(new
          {
            name = f.Name,
            size = f.Length,
            type = 1,// type = 1 - is file
            url = String.Format("http://{0}/{1}{2}{3}", Request.Url.Host + 
            (Request.Url.Port > 80 ? ":" + Request.Url.Port.ToString() : ""), 
            _Root, path, f.Name)
          }); 
        }
        // check top-level directory
        bool allowUp = !String.IsNullOrEmpty(path.Trim("/".ToCharArray()));
        // create JSON
        result = GetJsonString(new { stat = "ok", allowUp = allowUp, data = files });
        #endregion
      }
    }
    catch (Exception ex)
    {
      // error
      result = GetError(ex.Message);
    }

    // result
    return result.ToString();
  }

  /// <span class="code-SummaryComment"><summary>
</span>  /// The helper function returning error in the JSON
  /// <span class="code-SummaryComment"></summary>
</span>  /// <span class="code-SummaryComment"><param name="msg">Error message</param>
</span>  private StringBuilder GetError(string msg)
  {
    return GetJsonString(new { stat = "err", msg = msg });
  }

  /// <span class="code-SummaryComment"><summary>
</span>  /// The helper function for converting object to JSON
  /// <span class="code-SummaryComment"></summary>
</span>  /// <span class="code-SummaryComment"><param name="source">Object for converting JSON</param>
</span>  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
{
  /// <span class="code-SummaryComment"><summary>
</span>  /// The delegate  for callback function
  /// <span class="code-SummaryComment"></summary>
</span>  /// <span class="code-SummaryComment"><param name="stat">Server response code (ok, err)</param>
</span>  /// <span class="code-SummaryComment"><param name="msg">Error message  (only for stat = err)</param>
</span>  /// <span class="code-SummaryComment"><param name="allowUp">Has top-level directory</param>
</span>  /// <span class="code-SummaryComment"><param name="data">Array of file list</param>
</span>  public delegate void WebCallback
	(string stat, string msg, bool allowUp, JsonValue data, object tag);
  // public delegate void WebCallback(HttpWebResponse resp);

  private string _Method = "POST";
  private QueryItemCollection _Queries = new QueryItemCollection();
  private string _Url = String.Empty;

  private string _Boundary = String.Empty;
  private WebCallback _Callback = null;

  /// <span class="code-SummaryComment"><summary>
</span>  /// GET or POST
  /// <span class="code-SummaryComment"></summary>
</span>  public string Method
  {
    get
    {
      return _Method;
    }
    set
    {
      _Method = value;
      if (String.IsNullOrEmpty(_Method) || _Method.ToUpper() != "GET" || 
      	_Method.ToUpper() != "POST") _Method = "POST";
    }
  }

  /// <span class="code-SummaryComment"><summary>
</span>  /// Parameters of Request
  /// <span class="code-SummaryComment"></summary>
</span>  public QueryItemCollection Queries
  {
    get
    {
      return _Queries;
    }
    set
    {
      _Queries = value;
    }
  }

  /// <span class="code-SummaryComment"><summary>
</span>  /// Url for sending request
  /// <span class="code-SummaryComment"></summary>
</span>  public string Url
  {
    get
    {
      return _Url;
    }
    set
    {
      _Url = value;
    }
  }

  /// <span class="code-SummaryComment"><summary>
</span>  /// Additional custom property
  /// <span class="code-SummaryComment"></summary>
</span>  public object Tag { get; set; }

  public WebHelper(string url) : this (url, "POST") { }
  public WebHelper(string url, string method)
  {
    this.Url = url;
    this.Method = method;
  }

  /// <span class="code-SummaryComment"><summary>
</span>  /// Execute the Request
  /// <span class="code-SummaryComment"></summary>
</span>  /// <span class="code-SummaryComment"><param name="callback">The callback function</param>
</span>  public void Execute(WebCallback callback)
  {
    if (String.IsNullOrEmpty(_Url))
    {
      // url is empty
      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())
      {
        // has files, this is multipart/form-data content type
        _Boundary = "----------" + DateTime.Now.Ticks.ToString("x"); // random boundary
        myReq.ContentType = "multipart/form-data; boundary=" + _Boundary;
      }
      else
      {
        // has not files, this is application/x-www-form-urlencoded content type
        myReq.ContentType = "application/x-www-form-urlencoded";
      }
    }
    #endregion

    // start requests
    myReq.BeginGetRequestStream(Execute_BeginGetRequestStream, myReq);
  }
  private void Execute_BeginGetRequestStream(IAsyncResult result)
  {
    HttpWebRequest r = result.AsyncState as HttpWebRequest; // get request

    #region write parameters to request (only for POST)
    if (_Queries.Count >

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
{
  /// <span class="code-SummaryComment"><summary>
</span>  /// Item type: -1 - top-level directory, 0 - directory, 1 - file
  /// <span class="code-SummaryComment"></summary>
</span>  public int ItemType { get; set; }
  /// <span class="code-SummaryComment"><summary>
</span>  /// Directory/File name
  /// <span class="code-SummaryComment"></summary>
</span>  public string FileName { get; set; }
  /// <span class="code-SummaryComment"><summary>
</span>  /// File size (Kb)
  /// <span class="code-SummaryComment"></summary>
</span>  public double FileSize { get; set; }
  /// <span class="code-SummaryComment"><summary>
</span>  /// File url
  /// <span class="code-SummaryComment"></summary>
</span>  public string FileUrl { get; set; }
  /// <span class="code-SummaryComment"><summary>
</span>  /// True - item is in edit mode. 
  /// False - item is not in edit mode.
  /// <span class="code-SummaryComment"></summary>
</span>  public bool IsEdit { get; set; }
  /// <span class="code-SummaryComment"><summary>
</span>  /// Can edit the Item
  /// <span class="code-SummaryComment"></summary>
</span>  public bool CanEdit { get; set; }

  private string _NewName = "";
  /// <span class="code-SummaryComment"><summary>
</span>  /// New Directory/File name
  /// <span class="code-SummaryComment"></summary>
</span>  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; // top-level directory cannot be editable

    this.Orientation = Orientation.Horizontal;

    // item icon
    Image myImg = new Image() { Width = 16, Height = 16 };
    if (type == -1)
    {
      // top-level directory
      myImg.Source = new System.Windows.Media.Imaging.BitmapImage
		(new Uri("Images/folder2.png", UriKind.Relative));
    }
    else if (type == 0)
    {
      // directory
      myImg.Source = new System.Windows.Media.Imaging.BitmapImage
		(new Uri("Images/folder.png", UriKind.Relative));
    }
    else
    {
      // file
      // set icon by extension
      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
      {
        // default file icon
        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);

    // file/directory name
    this.Children.Add(new TextBlock() 
	{ Text = name, Margin = new Thickness(2, 0, 0, 0) });

    // control buttons
    // open file or go into directory
    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);

    // is not top-level directory
    if (type != -1)
    {
      // rename directory/file 
      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);

      // delete directory/file 
      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);
    }

    // file size
    if (type == 1) // only for files
    {
      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 >

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"; // gateway url for requests
private PleaseWait myPleaseWait = null;

public MainPage()
{
  InitializeComponent();

  fileList1.Url = _Url; //set url

  // handlers for progress
  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;
    // show porgress
    myPleaseWait = new PleaseWait();
    myPleaseWait.Show();
  });
}

private void fileList1_Complete(object sender, EventArgs e)
{
  this.Dispatcher.BeginInvoke(() =>
  {
    //close progress
    if (myPleaseWait != null)
    {
      myPleaseWait.Close();
      myPleaseWait = null;
    }
    // set new path from fileList
    tbPath.Text = fileList1.Path;
  });
}

For upload files, I created helper class UploadItem because sending is done in two stages:

  1. check
  2. upload
public class UploadItem
{
  /// <span class="code-SummaryComment"><summary>
</span>  /// The event occurs after the request is sent
  /// <span class="code-SummaryComment"></summary>
</span>  public event EventHandler Complete;

  /// <span class="code-SummaryComment"><summary>
</span>  /// State code list
  /// <span class="code-SummaryComment"></summary>
</span>  public enum StateList
  {
    /// <span class="code-SummaryComment"><summary>
</span>    /// File sent successfully
    /// <span class="code-SummaryComment"></summary>
</span>    OK,
    /// <span class="code-SummaryComment"><summary>
</span>    /// Error
    /// <span class="code-SummaryComment"></summary>
</span>    Error,
    /// <span class="code-SummaryComment"><summary>
</span>    /// File is waiting
    /// <span class="code-SummaryComment"></summary>
</span>    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;

  /// <span class="code-SummaryComment"><summary>
</span>  /// Upload state
  /// <span class="code-SummaryComment"></summary>
</span>  public StateList State
  {
    get { return _State; }
  }

  /// <span class="code-SummaryComment"><summary>
</span>  /// Error message
  /// <span class="code-SummaryComment"></summary>
</span>  public string Message
  {
    get { return _Message; }
  }

  /// <span class="code-SummaryComment"><summary>
</span>  /// File name
  /// <span class="code-SummaryComment"></summary>
</span>  public string FileName
  {
    get { return _FileName; }
  }

  /// <span class="code-SummaryComment"><summary>
</span>  /// File index
  /// <span class="code-SummaryComment"></summary>
</span>  public int Index
  {
    get { return _Index; }
  }

  /// <span class="code-SummaryComment"><param name="f">File</param>
</span>  /// <span class="code-SummaryComment"><param name="idx">File index</param>
</span>  /// <span class="code-SummaryComment"><param name="url">Url for uploading</param>
</span>  /// <span class="code-SummaryComment"><param name="path">Server path</param>
</span>  public UploadItem(int idx, FileInfo f, string url, string path)
  {
    _Index = idx;
      
    _Path = path;
    _Url = url;

    _FileName = f.Name; // set file name
    _FileStream = f.OpenRead(); // open file stream
  }

  public void Run()
  {
    try
    {
      // send request for check server
      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")
      {
        // send file
        WebHelper w = new WebHelper(_Url);
        w.Queries.Add("cmd", "upload");
        w.Queries.Add("path", _Path);
        w.Queries.Add("file1", _FileName, _FileStream);//add file to request
        w.Execute(UploadResult);
      }
      else
      {
        // error
        _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
    {
      // error
      _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)
{
  // add selected files to upload list
  FileInfo[] files = e.Data.GetData(DataFormats.FileDrop) as FileInfo[];
  foreach (FileInfo f in files)
  {
    this.AddUploadItem(f); 
  }

  // upload files
  this.Upload();
}

Uploading files starting on the Upload method each from _UploadList.

public void Upload()
{
  if (_UploadFiles == null || _UploadFiles.Count <= 0) return; // upload list is empty
      
  _UploadErrorMessages = new StringBuilder();

  if (Process!=null) Process(this, null);;

  foreach (UploadItem itm in _UploadFiles)
  {
    itm.Run();//start upload file
  }
}

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);
    }
    // remove file from upload list
    _UploadFiles.Remove(itm);
    if (_UploadFiles.Count == 0)
    {
      // upload list is empty
      // start Complete
      if (Complete != null) Complete(this, null);
      // has error?
      if (_UploadErrorMessages.Length <= 0)
      {
        // no error, update file list
        UpdateFileList();
      }
      else
      {
        // show error message
        ShowError(_UploadErrorMessages.ToString());
      }
    }
  });
}

The entire code of the FileList class.

public class FileList : ListBox
{

  /// <span class="code-SummaryComment"><summary>
</span>  /// The event occurs before the request is sent
  /// <span class="code-SummaryComment"></summary>
</span>  public event EventHandler Process;
  /// <span class="code-SummaryComment"><summary>
</span>  /// The event occurs after the request is sent
  /// <span class="code-SummaryComment"></summary>
</span>  public event EventHandler Complete;

  private string _Url = "";
  private string _Path = "/";
  private List<UploadItem> _UploadFiles = null; // the file list to upload 
  private StringBuilder _UploadErrorMessages = null; // upload error messages

  /// <span class="code-SummaryComment"><summary>
</span>  /// The path of the directory on the server
  /// <span class="code-SummaryComment"></summary>
</span>  public string Path
  {
    get
    {
      return _Path;
    }
    set
    {
      _Path = value;
      if (String.IsNullOrEmpty(_Path)) _Path = "/";
    }
  }

  /// <span class="code-SummaryComment"><summary>
</span>  /// The file list to upload 
  /// <span class="code-SummaryComment"></summary>
</span>  public List<UploadItem> UploadFiles
  {
    get
    {
      return _UploadFiles;
    }
  }

  /// <span class="code-SummaryComment"><summary>
</span>  /// Gateway url
  /// <span class="code-SummaryComment"></summary>
</span>  public string Url
  {
    get
    {
      return _Url;
    }
    set
    {
      _Url = value;
      if (!System.ComponentModel.DesignerProperties.IsInDesignTool)// is not 
							// Visual Studio designer
      { //update file list
        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); // add KeyUp handler
    this.Drop += new DragEventHandler(FileList_Drop); // add Drop handler
  }

  /// <span class="code-SummaryComment"><summary>
</span>  /// FileList KeyUp handler
  /// <span class="code-SummaryComment"></summary>
</span>  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)
    { // open file or go into the directory
      itm.Open();
    }
    else if (e.Key == Key.Enter && itm.IsEdit)
    { // finish editing
      itm.EditComplete();
    }
    else if (e.Key == Key.F2 && itm.CanEdit && !itm.IsEdit)
    { // start editing
      itm.EditStart();
    }
    else if (e.Key == Key.Escape && itm.IsEdit)
    { // cancel editing
      itm.EditCancel();
    }
    else if (e.Key == Key.Delete && !itm.IsEdit)
    { // delete file or directory
      itm.Delete();
    }
    else if (e.Key == Key.F5)
    { // update file list
      UpdateFileList();
    }
  }

  #region update file list
  /// <span class="code-SummaryComment"><summary>
</span>  /// Send request to the server for a list of files
  /// <span class="code-SummaryComment"></summary>
</span>  public void UpdateFileList()
  {
    if (Process!=null) Process(this, null);; // start Process

    // send request
    WebHelper w = new WebHelper(this.Url);
    w.Queries.Add("cmd", "get");
    w.Queries.Add("path", _Path);
    w.Execute(UpdateFileListResult); // the server response 
    		//we can find in the UpdateFileListResult method
  }
  private void UpdateFileListResult
  (string stat, string msg, bool allowUp, JsonValue data, object tag)
  {
    if (stat == "ok")
    {
      // crear FileList items
      this.Dispatcher.BeginInvoke(() =>
      {
        this.Items.Clear();
      });

      // add top-level directory
      if (allowUp)
      {
        AddItem(-1, "...", "", 0);
      }

      // add files and directories
      if (data != null && data.Count >

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"; // you gateway url
  // http://localhost:58646 - is default address for solution but maybe another
}

Enjoy!

License

This article, along with any associated source code and files, is licensed under The Common Public License Version 1.0 (CPL)

Share

About the Author

Alеksey Nemiro
Web Developer Kbyte.Ru
Russian Federation Russian Federation
Web Developer. Writer. Author of the Kbyte.Ru.
I like ASP .NET WebForms/MVC, C#, Visual Basic .NET, T-SQL, JavaScript, HTML, CSS, PHP.
Follow on   Twitter

Comments and Discussions

 
QuestionMy vote of 5 Pinmemberliviucatrina8-May-12 22:01 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.150414.1 | Last Updated 8 Jan 2012
Article Copyright 2012 by Alеksey Nemiro
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid