Introduction
I don't know if this dialog will be helpful to anyone else, but I am writing an application for interfacing with websites, editing them, and so forth, and I need a text box in the application populated with a link to a resource. At first, I just left it to the user to properly type in the resource URL, but then I got to thinking that it would be nice to be able to browse to the resource, choose it, then have the text box populated with the link based on the chosen file. This dialog achieves this.
Using the code
There are two constructors available for the dialog:
FtpBrowseDialog();
FtpBrowseDialog(String host, String startpath, int port, String username, String password, bool passivemode);
The base constructor will open the dialog, with a nested dialog prompting for connection variables:
- Server (host) - enter the domain without "ftp://", the dialog will add this for you.
- Start path (optional) - controls the subdirectory that the dialog starts in.
- Port - TCP port to be used, default FTP port is 21.
- Username - username for connection.
- Password - password for connection.
- Use Passive checkbox - controls whether connecting to a passive FTP or not, default is checked for yes.
The other constructor allows you to pass all these variables, suppressing the connection prompt.
Once connected, another subdialog will show, with a marquee progress bar while the FTP file structure is loaded. Once loaded, the progress dialog will close, and access to the file structure will be available.
If you would like to see how the UI works without loading a server, you can use the TestMode
property. Set this to true
before calling ShowDialog()
, and a mock file structure will be loaded that you can use for testing purposes.
Here is the basic working of the UI. I tried to mimic the OpenFileDialog
as much as I could, but there are some features still lacking I'm sure; any suggestions are welcome for future revisions:
- Selecting a folder on the left will populate that folder's subfolders and files on the right.
- The OK button remains disabled until an actual file is selected in the right panel.
- Two toolbar buttons are provided:
- The button to the left moves up a directory, and disables once the root folder is reached.
- The button to the right allows you to open a new server structure, the connection details subdialog will show, defaulting to the current connection information, but will allow you to enter new information and click Connect to load a new server.
- Double clicking on a file in the right panel will automatically select the file and close the dialog.
- Double clicking a subfolder in the right panel will move to that folder.
- When the right panel is focused, pressing backspace will mimic the up directory toolbar button.
Once either a file is double clicked, or the OK button is pressed, then DialogResult.OK
is returned and the file info can be collected from the calling form. There are three options for acquiring the selected file information:
FtpBrowseDialog.SelectedFile
- returns file in FQN form with FTP references.FtpBrowseDialog.SelectedFileName
- returns the file name only.FtpBrowseDialog.SelectedFileUrl
- returns the file in a web friendly fashion for link purposes (note: this also replaces all spaces in the file name with %20).
Points of interest (My approach)
If you are new to programming, you may be asking "How did he do this?!?" And if you are a pro, you will probably be wondering "Why did he do this?!?"
Here are the basics of the project. First, I created a new TreeNode
class called FtpTreeNode
, and gave it a few extra properties and methods:
FtpTreeNode.Files
- A StringCollection
holding all the file names for the folder this node represents.FtpTreeNode.Directories
- A StringCollection
holding all the subdirectory names for the folder this node represents.
FtpTreeNode.AddFile(String file)
- adds a file to the collection.FtpTreeNode.AddDirectory(String dir)
- adds a directory to the collection.FtpTreeNode.Select()
- handles minute details involved with what needs to happen when a node is selected.
FTP information is collected by juggling between an FtpWebRequest
and an FtpWebResponse
. You may have stumbled on this looking for an answer to how to control the port variable of a FtpWebRequest
, without having to hard code it into the connection string using the ":" character. Well, the answer is simple, but took me a bit to find. Using an instance of UriBuilder
will accomplish this. With a UriBuilder
, you supply the protocol type "ftp" and the host domain, along with the port number and a starting path string. There are a few different constructors which will allow some of these specifics to be optional. Here is an example of the URI that I built for populating the dialog.
UriBuilder ub = new UriBuilder("ftp", host, port, startpath);
I had to use startpath
because I wanted only the root node to have the FQN, and each subnode to only show the directory name.
Something else I had to figure out was that FtpWebRequest
has a UsePassive
property that controls whether to connect using PASV or not. Older servers do not use passive mode, most new ones do. Also, you can control the username and password by setting the Credential
property of the FtpWebRequest
.
FtpWebRequest req = new FtpWebRequest(ub.Uri);
req.Credential = new NetworkCredential(username, password);
bool passivemode = true;
req.UsePassive = passivemode;
Now for the fun part. I had to use method recursion to accomplish the file structure load. There is a method in FtpBrowseDialog
called LoadSubNodes
.
private void LoadSubNodes(FtpTreeNode node)
This method sets request.Method
to WebRequestMethods.Ftp.ListDirectroyDetails
, gets a response based on the supplied node's FTP URL, and then parses the response to get all the directories and files added to the node, and then creates a subnode for each directory and passes it back into LoadSubNodes
, that is where the recursion comes in. Once all sub directory nodes are loaded and added into this node's subnodes, then the method returns. All that needs to be done to kick this party off is to create a root node and pass it into LoadSubNodes
; once that returns, add the root node to the TreeView
.
History
- October 2, 2008 - v1.0 - Initial post.
Next version plans:
- Allow disabling of the Open New Server button, allowing you to lock a user to a specified server.
- Make it easier to add custom images to the file list panel for different file types.
- Provide a file filter property, allowing you to control which file types are supported by the dialog.