views:

522

answers:

4

I am using MVVM as my WPF architecture and I have a WPF TreeView implemented as delay loading (child items are not loaded recursively until you expand).

However, I need to implement asynchronous loading as well upon expansion. Is there a way to do that? I need to keep this in control level and not in code-behind/application level.

Thanks

A: 

Why do you need to implement this in the control itself?

Assuming that isn't an absolute requirement, I would handle this in the property that returns the children of the specified node. If the children haven't been populate yet, use a background thread to load the children, and as they are found notify the UI thread and then add the child object to the collection of children. Assuming that you're using an ObservableCollection (or at least a collection that implements INotifyCollectionChanged), as the children are added they will appear in the UI asynchronously.

Andy
A: 

If you use lazy loading and HierarchicalDataTemplates you will only get the items you've selected loading. Keep in mind, the TreeView will need to load one level below what it is displaying to determine whether or not it should show the Expand/Collapse Toggle button

Nick
A: 

For every UI element that needs delayed loading I have used a 'View GUID'.

Explanation by example:

  1. At the beginning, Control.Tag = "0000-0000 ...."
  2. User makes an interaction,
    • a random GUID is generated, namely, guid1
    • Control.Tag = guid1
    • a thread is created which takes (what do to, control, guid1)
  3. in between, the user makes another interaction
    • a random GUID is generated (guid2 this time)
    • Control.Tag = guid2
    • a thread is created which takes (what do to, control, guid2)
  4. The first thread finishes:
    • it invokes a code into UI thread which takes results and the guid it got before execution
    • the invoked code checks that Control.Tag != guid1, makes no changes
  5. The second thread finishes:
    • it invokes a code into UI thread which takes results and the guid it got before execution
    • the invoked code sees that Control.Tag == guid2, makes changes
modosansreves
What in the world? This is WPF. Why you you use a Tag property and strings for this? Why would you require your custom code to run on every user interaction? It sounds like you're talking about more primitive technologies like WinForms or Flash/AIR, in which this would be necessary. And it is not clear how this would interact with a TreeView. IMHO this does not answer the question at all.
Ray Burns
I agree about using Tags: using own's dependency property is a better choice.
modosansreves
When `GetChildren()` is expected to take time, doing the call in a separate thread makes sense. There is a problem of synchronization then, and guids are there to solve it.
modosansreves
A: 

Here is how to do this:

  1. Create an attached property of type IEnumerable
  2. In the PropertyChanged handler for the property, cast sender to TreeViewItem and check the IsExpanded property.
  3. If IsExpanded is true, do a Dispatcher.BeginInvoke at ApplicationPriority.ApplicationIdle priority to your fill routine
  4. If IsExpanded is false, set an event to detect when it becomes true and in the callback do the Dispatcher.BeginInvoke to your fill routine
  5. In your fill routine, set the ItemsSource of the target control to the attached property value
  6. Use a style to set your attached property on TreeViewItem instead of setting it through HierarchicalDataTemplate (omit ItemsSource there)

This prevents the TreeViewItem from ever having its ItemsSource set until it is expanded. Creating this mechanism is some work, but once it is created you can make any TreeView delay-load by simply removing the ItemsSource from the HierarchicalDataTemplate and setting it in your ItemContainerStyle instead.

Ray Burns