tags:

views:

1124

answers:

2

Intention: To display the busy/Wait cursor for the duration that the children of the node are populated.

Seems to be hidden in WPF. I remember having some kind of event in Winforms Tree Control where you could subscribe to - to achieve this.

Currently I have a TreeView which has a number of listviews tied to its SelectedItem. All controls are databound and use DataTemplates to display the items. The code is functional. But when I expand a tree-node with a lot of children, the UI goes sluggish.. it looks like the click didnt register.. and I being the impatient user go clickety-click on the node.

So how do I do this ? I'd like to set the Cursor to Wait in BeforeExpand and reset in AfterExpand.

Code Scribble:

<HierarchicalDataTemplate DataType="{x:Type local:LinqToSqlNodeClass}" ItemsSource="{Binding Path=Children}">
  // visual representation
</HierarchicalDataTemplate>
// more typed data templates 

<TreeView ItemsSource="{Binding Path=Nodes}" />
A: 

Edit - The only way to accomplish this would be to make a class derived from TreeViewItem and override the OnExpand and setup a new Expanding Routed Event before you call the base Expand. Then you will use this new class as your container, instead of the default TreeViewItem.

Then you could do something like

<TreeView cust:CustomTreeViewItem.Expanding="TreeView_Expanding">....</TreeView>

Previous Answer....

The only thing I can see you using is the Collapsed and Expanded events on the TreeViewItem.

You will have to change your template to use a TreeViewItem, with the events defined.

Will this work for your purposes?

Jab
The Expanded event I'm guessing will fire *after* the node has expanded.. I want to show the busy cursor during the interval where the user action (double click or right arrow) and the node actually expands. That is the part which is taking a long time.
Gishu
A: 

The ItemContainerGenerator will start generating after the Expanded event, so you can use that to set the Cursor, and set it back once ItemContainerGenerator.StatusChanged fires to indicate that your children have been populated.

Since TreeViewItem.Expanded is a routed event, you can just subscribe at some parent level:

myTreeView.AddHandler(TreeViewItem.ExpandedEvent, new RoutedEventHandler(TreeViewItemExpanded));

Where TreeViewItemExpanded is defined elsewhere, something like this:

private void TreeViewItemExpanded(object sender, RoutedEventArgs e)
{
    // we will only go through with this if our children haven't been populated
    TreeViewItem sourceItem = e.OriginalSource as TreeViewItem;
    if ((sourceItem != null)
        && (sourceItem.ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated))
    {
        // create a handler that will check our children and reset the cursor when the ItemContainerGenerator has finished
        EventHandler itemsGenerated = null;
        DateTime before = DateTime.Now;
        itemsGenerated = delegate(object o, EventArgs args)
        {
            // if the children are done being generated...
            if ((o as ItemContainerGenerator).Status == GeneratorStatus.ContainersGenerated)
            {
                (o as ItemContainerGenerator).StatusChanged -= itemsGenerated;  // we're done, so remove the handler
                sourceItem.Dispatcher.BeginInvoke(DispatcherPriority.DataBind, (ThreadStart)delegate    // asynchronous reset of cursor
                {
                    myWindow.Cursor = Cursors.Arrow;    // reset cursor
                    Debug.WriteLine("Expanded in " + (DateTime.Now - before));
                });
            }
        };
        sourceItem.ItemContainerGenerator.StatusChanged += itemsGenerated;  // add the handler
        myWindow.Cursor = Cursors.Wait;     // wait cursor
    }
    e.Handled = true;
}
Robert Macnee