Loading sub items of TreeView in background I am working with a TreeView (default control from .Net Framework) that displays hierachical data. Data are bound to the view using MVVM pattern with the HierarchicalDataTemplate.

&lt;HierarchicalDataTemplate DataType="{x:Type models:TreeItemViewModel}" ItemsSource="{Binding Children, Mode=OneWay}"&gt;
    &lt;TextBlock Text="{Binding Name}" /&gt;
&lt;/HierarchicalDataTemplate&gt;


The child items are loaded automatically when the view requests the child collection. To stay responsive, the child items are loaded in background up to a specific depth:

public class TreeItemViewModel : ViewModelBase
{
    private readonly ObservableCollection&lt;TreeItemViewModel&gt; myChildren = new ObservableCollection&lt;TreeItemViewModel&gt;();
    private const int PRELOADING_DEPTH = 1;

    public string Name { get; set; }
    public bool IsLoaded { get; set; }
    public bool IsLoading { get; set; }

    public ObservableCollection&lt;TreeItemViewModel&gt; Children
    {
        get
        {
            ThreadPool.QueueUserWorkItem(o =&gt; EnsureChildrenAreLoaded(myChildren, 0));
            return myChildren;
        }
    }

    public void EnsureChildrenAreLoaded(ObservableCollection&lt;TreeItemViewModel&gt; childrenToFill, int depth)
    {
        if (!IsLoaded &amp;&amp; !IsLoading)
        {
            IsLoading = true;
            var children = LoadChildren().ToArray();
            App.RunOnGuiThread(() =&gt;
            {
                foreach (var child in children)
                    childrenToFill.Add(child);
                IsLoaded = true;
                IsLoading = false;
            });
        }
        if (depth &lt; PRELOADING_DEPTH)
            foreach (var child in myChildren)
                child.EnsureChildrenAreLoaded(child.myChildren, depth + 1);
    }

    protected virtual IEnumerable&lt;TreeItemViewModel&gt; LoadChildren()
    {
        // logic for loading sub items
        return Enumerable.Empty&lt;TreeItemViewModel&gt;();
    }
}


RunOnGuiThread:

    public static void RunOnGuiThread(Action action)
    {
        if (Current == null || Current.Dispatcher == null)
            action();
        else
            Current.Dispatcher.Invoke(action);
    }


Is that a proper solution? Has it any disadvantages / potential for improvements?
I do not see your full UI then maybe you're using it (to display a busy indicator?) but, from what I have here, it seems that IsLoading is just a repetition for IsLoaded and as such it should be dropped. Any reason for EnsureChildrenAreLoaded() to be public and TreeItemViewModel not to be sealed?

EnsureChildrenAreLoaded() might be:

var children = LoadChildren().ToArray();
App.RunOnGuiThread(() =&gt;
{
    foreach (var child in children)
        childrenToFill.Add(child);

    IsLoaded = true;
});


However we now have the problem to preload the children. My major concern here is that you're queuing an action in the pool each time you read the property. Not such big overhead but avoidable. Also I'd move this responsibilities to separate methods:

void LoadChildrenAndUpdateUi(ObservableCollection&lt;TreeItemViewModel&gt; childrenToFill)
{
    IsLoaded = true;

    var children = LoadChildren().ToArray();
    App.RunOnGuiThread(() =&gt;
    {
        foreach (var child in children)
            childrenToFill.Add(child);
    });
}


And:

ObservableCollection&lt;TreeItemViewModel&gt; EnsureChildrenAreLoaded(
    ObservableCollection&lt;TreeItemViewModel&gt; childrenToFill, int depth)
{
    if (depth &gt;= PRELOADING_DEPTH)
        return;

    if (!IsLoaded)
        ThreadPool.QueueUserWorkItem(_ =&gt; LoadChildrenAndUpdateUi(myChildren));

    foreach (var child in myChildren)
        child.EnsureChildrenAreLoaded(child.myChildren, depth + 1);

    return myChildren;
}


Our getter will then be:

public ObservableCollection&lt;TreeItemViewModel&gt; Children
    =&gt; EnsureChildrenAreLoaded(myChildren, 0);


Major difference is that we're going through the children to determine if they have to be loaded in the calling UI thread but we're queuing an action in the thread pool only when required. Note that we're using only one property to track the state (IsLoaded, which should be private). I set its value to true before effectively reading children to avoid multiple parallel requests, name is now somehow misleading and should be changed to something meaningful (_isVisited or something like that).

What next? If PRELOADING_DEPTH might ever be 0 or loading time may be really long then I'd add a dummy item to the child collection (to display the expand/collapse indicator), something like:

public TreeItemViewModel()
{
    Children.Add(new TreeItemViewModel { Name = "Loading..." });
}


Removed before you start adding new items:

children.Clear();
foreach (var child in children)
    childrenToFill.Add(child);


But, well, you already have a busy indicator then you don't need this at all!



Edit: if you're using IsLoading in your UI then, unfortunately, you can't drop it that easily. I think you have two options: replace IsLoading and IsLoaded with an enum like enum LoadingStatus { NotLoaded, Loading, Loaded } used in conjunction with a value converter to hide/show the busy indicator or use ordering (as you already doing) to avoid locks (because fortunately you have only one thread for writing):

var children = LoadChildren().ToArray();
App.RunOnGuiThread(() =&gt;
{
    foreach (var child in children)
        childrenToFill.Add(child);

    IsLoaded = true;
    IsLoading = false;
});


Set IsLoading in the UI thread to avoid race conditions (both read and write will be then done in the same UI thread):

if (!IsLoaded &amp;&amp; !IsLoading)
{
    IsLoading = true;
    ThreadPool.QueueUserWorkItem(_ =&gt; LoadChildrenAndUpdateUi(myChildren));
}




Final notes.

If your depth is limited to direct children then you  may simplify your implementation (just invoke the lazy load method when you populate the list). You may also want to try to use a LazyAsync&lt;T&gt; implementation (I saw a nice one somewhere...can't find/remember where).

WPF supports asynchronous binding with a simple IsAsync=true in the binding expression. You may want to experiment with that, see MSDN for details