The Tricks with TreeViewItem Expansion (Revisited)

| 1 comments

Last year, I posted a blog article talking about how to expand TreeViewItems, unfortunately, the download link to the source code of that article was broken, and what's more, I lost the original source code myself, so in today's post, I want to revisit this topic with the core piece of code which actually does the trick.

using System;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;

namespace Sheva.Windows.Controls
{
    public static class TreeViewHelper
    {
        public static void ExpanAll(TreeView treeView)
        {
            ExpandSubContainers(treeView);
        }

        private static void ExpandSubContainers(ItemsControl parentContainer)
        {
            foreach (Object item in parentContainer.Items)
            {
                TreeViewItem currentContainer = parentContainer.ItemContainerGenerator.ContainerFromItem(item) as TreeViewItem;
                if (currentContainer != null && currentContainer.Items.Count > 0)
                {
                    currentContainer.IsExpanded = true;
                    if (currentContainer.ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated)
                    {
                        currentContainer.ItemContainerGenerator.StatusChanged += delegate
                        {
                            ExpandSubContainers(currentContainer);
                        };
                    }
                    else
                    {
                        ExpandSubContainers(currentContainer);
                    }
                }
            }
        }
    }
}

The key caveat of expanding TreeViewItems is to make sure that the container for the current TreeViewItem has been generated, so you can safely expand it to show all its sub items, that's why I make recursive call when the status of current TreeViewItem's ItemContainerGenerator is set to GeneratorStatus.ContainersGenerated.

Delegate.BeginInvoke vs ThreadPool.QueueUserWorkItem

| 3 comments

Today, I come across Chris Brumme's blog on TransparentProxy, I really enjoy his blog, in particular those dedicated to the inner-working of CLR, one of the surprising sentence I read from his TransparentProxy article is that:

One surprising fact is that this is also why Delegate.BeginInvoke / EndInvoke are so slow compared to equivalent techniques like ThreadPool.QueueUserWorkItem (or UnsafeQueueUserWorkItem if you understand the security implications and want to be really efficient). The codepath for BeginInvoke / EndInvoke quickly turns into the common Message processing code of the general remoting pathway.

   I have to say I get pretty stunned when reading this, so I write a little piece of code to verify his allegation:

using System;
using System.Threading;
using System.Diagnostics;

namespace DelegatePerformance
{
    class Program
    {
        static void Main(string[] args)
        {
            ThreadStart threadStart = new ThreadStart(() => { });
            WaitCallback waitCallback = new WaitCallback(a => { });
            Stopwatch stopWatch = new Stopwatch();

            stopWatch.Start();
            for (int i = 0; i < 10000; i++)
            {
                threadStart.BeginInvoke(null, null);
            }
            stopWatch.Stop();
            Console.WriteLine("Delegate.BeinInvoke(): {0}",stopWatch.ElapsedTicks.ToString());

            stopWatch.Reset();
            stopWatch.Start();
            for (int i = 0; i < 10000; i++)
            {
                System.Threading.ThreadPool.QueueUserWorkItem(waitCallback);
            }
            stopWatch.Stop();
            Console.WriteLine("ThreadPool.QueueUserWorkItem(): {0}", stopWatch.ElapsedTicks.ToString());
        }
    }
}

And the following output is what I get when running above programme:

Delegate.BeinInvoke(): 591441
ThreadPool.QueueUserWorkItem(): 91958

From the output, there is no brainer that Delegate.BeginInvoke is way much slower than the ThreadPool.QueueUserWorkItem call.