P0tat0627
P0tat0627

Reputation: 29

Populating TreeView from FTP directory in .NET Framework only after node is expanded

I have a server hosted in my Linux PC. Now I am creating a FTP client with some specific tools to handle. Now I want to generate my a TreeView in my windows form. I have already generated a treeview but it takes too much to login cause listing all the directories and sub directories take big amount of time when the directories increase. I want to load only the first layer of directories then when user clicks on the expand ('+') button then it should populate the directories under that and like it. How this can be done? My current treeview code look like this

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Windows.Forms;

namespace GISFileManagerClient
{
    public class TreeView
    {
        public FtpWebResponse PopulateDirectories(TreeNode parentNode,
            string ftpRootPath,
            string hostUsername,
            string hostPassword,
            FtpWebRequest request,
            FtpWebResponse response
            )
        {
            try
            {
                // ftp request for each directory list
                request = (FtpWebRequest)WebRequest.Create(ftpRootPath);
                request.Credentials = new NetworkCredential(hostUsername, hostPassword);
                request.Method = WebRequestMethods.Ftp.ListDirectory;
                request.KeepAlive = true;

                response = (FtpWebResponse)request.GetResponse();
                Stream responseStream = response.GetResponseStream();
                StreamReader reader = new StreamReader(responseStream);

                string directoryContents = reader.ReadToEnd();
                string[] directories = directoryContents.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);

                List<string> modifiedDirectories = new List<string>();

                foreach (string directory in directories)
                {
                    // splitting directory name for refined folder
                    string[] parts = directory.Split('/');

                    // getting last string after '/' as that will be present directory "AWGSS/DG" will give DG
                    string modifiedDirectory = parts[parts.Length - 1];

                    // refined directories name to remove confusion
                    modifiedDirectories.Add(modifiedDirectory);
                }

                // converting list to string array before passing
                string[] finalDirectories = modifiedDirectories.ToArray();

                foreach (string directory in finalDirectories)
                {
                    // creating node for each directory
                    Console.WriteLine($"directory looks like this: {directory}");

                    TreeNode node = new TreeNode(directory);
                    parentNode.Nodes.Add(node);

                    Console.WriteLine($"new stream looks like this: {ftpRootPath}/{Path.GetFileName(directory)}");
                    // condition to differentiate between file and directory
                    bool isDirectory = Path.GetFileName(directory).Contains(".");

                    if (isDirectory)
                    {
                        continue;
                    }
                    else
                    {
                        PopulateDirectories(node, $"{ftpRootPath}/{Path.GetFileName(directory)}", hostUsername, hostPassword, request, response);
                    }
                }
                reader.Close();

            }
            catch (WebException ex)
            {
                // Handle exception
                // MessageBox.Show($"Error: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);

                Console.WriteLine($"Error: {ex.Message}");
            }
            return response;
        }
    }
}


Tried to populate treeview directories frequently.

Expecting to populate subs on user clicking on expand button, not before.

Upvotes: 1

Views: 49

Answers (1)

Martin Prikryl
Martin Prikryl

Reputation: 202534

Implement the TreeView.BeforeExpand event to populate the node only once the user expands it: https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.treeview.beforeexpand

You will also have to make sure the expand button shows even for nodes that were not visited yet. While technically the underlying Windows Tree-view control does allow that (see TVIF_CHILDREN), this functionality does no seem to be exposed in WinForms. You will either have to implement that using P/Invoke (while it's doable, it's a lot of work, as the API is complex), or just add a fake child node to not-yet-populated nodes.

Related questions:


You should also consider populating the tree from a background thread, not to block the GUI thread. And that will actually allow you to populate whole tree on the background, not only once the user expands a node. But that's for another question.

Upvotes: 1

Related Questions