1
votes

Just a quick one on dependency properties. I have a treeview I'm lazy loading, binding with an MVVM model. On the bound property IsExpanded, I have this code

public bool IsExpanded
        {
            get { return _isExpanded; }
            set
            {
                if (value != _isExpanded)
                {
                    _isExpanded = value;
                    OnPropertyChanged("IsExpanded");
                }

                // Expand all the way up to the root
                if (_isExpanded && _parent != null)
                    if (!_parent.IsExpanded) _parent.IsExpanded = true;

                // Lazy load the child items, if necessary
                if (HasDummyChild)
                {
                    LoadChildren();
                }
            }
        }

Which is fired when you click on the expand icon on the node, it then loads the children, and when that completes, it displays the child nodes expanded.

The problem is this can take a little bit of time to load, so while it is loading I want to have a single child saying something like "Please wait, loading..." and then when the LoadChildren() method completes, it then displays the actual children.

I am adding a dummy node to the children list by default, which has this display text, then calling LoadChildren and replacing that dummy list with the actual one but the issue is when you click on the expand icon, the setter fires first, which needs to fully complete before the GET data binding gets called to display the children.

So the dummy item never gets displayed, it exists in the children list but by the time the setter completes, it has been replaced and the only thing that ever gets displayed is the full list with a pause before opening it.

is there a way you can think of so that when you click the icon, it visually expands the node with the existing dummy child FIRST, and THEN tries to fetch and load the actual children?

1

1 Answers

1
votes

You would need to perform the loading in a background thread. Adding the loaded children to the list however needs to be performed on the UI thread.

Something like this:

public void AddChildrenAsync()
{
    var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
    Task.Factory.Run(() => LongOperationThatReturnsTheChildren(); )
                .ContinueWith(t =>
                              {
                                  Children.AddRange(t.Result);
                                  Children.RemoveAt(0);
                              }, uiScheduler);
}

In the setter:

// Lazy load the child items, if necessary
if (HasDummyChild)
{
    LoadChildrenAsync();
}