0

I am trying to implement lazy tree loading in WPF. I have a TreeView which I populate with some nodes. Each node has a subnode with a "Loading..." header. What I want to achieve is:

  1. User expands top node.
  2. Top node expands and shows the "Loading..." subnode.
  3. After the loading node is shown, method foo determines what subnodes to be added.
  4. When the work is done, the "Loading..." node is removed and the new nodes which method foo has created are shown.

The idea is to send feedback to the user that the tree is loading since it takes quite some time for my foo() method to run.

The code which I have is this:

<TreeView x:Name="MyTree" TreeViewItem.Expanded="MyTreeItem_Expanded" ItemsSource="{Binding}">

private void MyTreeItem_Expanded(object sender, RoutedEventArgs e) {
    // some logic to figure out from which node the event has been risen

    // method foo adds the new subnodes

    // code which removes the "Loading..." subnode
}

With this implementation, when I click on the node, the tree freezes and the node expands only after foo() is done and "Loading..." is removed.

How can I first show the "Loading..." node and then do the loading?

1 Answer 1

1

since everything is happening on the main ui thread items seems like the treeview is freezing. if possible process the foo on background worker. below is modified sample from wpf-tutorial.com . This is not an optimized solution but will give you an idea.

      BackgroundWorker bgworker = new BackgroundWorker();
    public MainWindow()
    {
        InitializeComponent();
        bgworker.DoWork += bgworker_DoWork;
        DriveInfo[] drives = DriveInfo.GetDrives();
        foreach (DriveInfo driveInfo in drives)
            trvStructure.Items.Add(CreateTreeItem(driveInfo));            
    }
    private void trvStructure_Expanded(object sender, RoutedEventArgs e)
    {
        TreeViewItem item = e.Source as TreeViewItem;
        bgworker.RunWorkerAsync(item);
    }
    void bgworker_DoWork(object sender, DoWorkEventArgs e)
    {          
        TreeViewItem item = (TreeViewItem)e.Argument;
        LoadFiles(item);           
    }
    void LoadFiles(TreeViewItem item)
    {
        System.Threading.Thread.Sleep(1000);
        item.Dispatcher.BeginInvoke(new Action<TreeViewItem>(AddItems), item);

    }      

    void AddItems(TreeViewItem item)
    {

        if ((item.Items.Count == 1) && (item.Items[0] is string))
        {
            item.Items.Clear();
            DirectoryInfo expandedDir = null;
            if (item.Tag is DriveInfo)
                expandedDir = (item.Tag as DriveInfo).RootDirectory;
            if (item.Tag is DirectoryInfo)
                expandedDir = (item.Tag as DirectoryInfo);
            try
            {
                foreach (DirectoryInfo subDir in expandedDir.GetDirectories())
                {
                    item.Items.Add(CreateTreeItem(subDir));

                }
            }
            catch { }
        }

    }
    private TreeViewItem CreateTreeItem(object o)
    {
        TreeViewItem item = new TreeViewItem();
        item.Header = o.ToString();
        item.Tag = o;
        item.Items.Add("Loading...");
        return item;
    }      

in LoadFiles(TreeViewItem item) System.Threading.Thread.Sleep(1000); is giving UI time to expand.

Sign up to request clarification or add additional context in comments.

1 Comment

I had tried with loading from another thread but it didn't work. The missing component was Sleep(1000); Thanks for helping!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.