none
WPF Teeview Creation in Thread

    Question

  • We have an API that creates a Forms TreeNode, the root for a Forms TreeView. This process takes a couple of seconds so the users normally do this in a separate thread. Works great.

    Now we have a new user that uses WPF and wants the same Treeview. We created a new method, a copy of the windows forms method, made a few changes and the WPF treeview was created.

    However the WPF code can't be created on a separate thread. Apparently all UI elements must be created on the dispatcher thread.

    Am I missing something? This WPF Me.Loaded event code illustrates the problem
            t = Task.Run(Sub()
                             Dim tvI As New TreeViewItem 'errors here.
                             tvI.Items.Add("Root")
                         End Sub)


    Search Documentation

    SerialPort Info

    Multics - An OS ahead of its time.

     "Those who use Application.DoEvents have no idea what it does

        and those who know what it does never use it."    former MSDN User JohnWein

    Thursday, May 16, 2019 2:20 PM

All replies

  • Hi,
    the best way is to bind the TreeView.ItemsSource to a collection of data objects, execute the long-time method in separate thread and only the Add of new data object execute via Dispatcher.Invoke like in this demo:

    <Window x:Class="Window32"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WpfApp1"
            mc:Ignorable="d"
            Title="Window32" Height="450" Width="800">
      <Window.DataContext>
        <local:Window32VM/>
      </Window.DataContext>
      <Grid>
        <TreeView ItemsSource="{Binding View}">
          <TreeView.Resources>
            <HierarchicalDataTemplate DataType="{x:Type local:Window32Data}">
              <Label Content="{Binding Info}"/>
            </HierarchicalDataTemplate>
          </TreeView.Resources>
        </TreeView>
      </Grid>
    </Window>

    ViewModel and data class:

    Imports System.Collections.ObjectModel
    Imports System.ComponentModel
    Imports System.Runtime.CompilerServices
    
    Public Class Window32VM
      Implements INotifyPropertyChanged
    
      Public Sub New()
        Dim t = Task.Run(New Action(Async Sub()
                                      For i = 1 To 100
                                        Await Task.Delay(500)
                                        Dim d As New Window32Data With {.Info = $"Node {i:000}"}
                                        Application.Current.Dispatcher.Invoke(Sub()
                                                                                col.Add(d)
                                                                                OnPropChanged(NameOf(View))
                                                                              End Sub)
                                      Next
                                    End Sub))
        cvs.Source = col
      End Sub
    
      Private col As New ObservableCollection(Of Window32Data)
      Private cvs As New CollectionViewSource
    
      Public ReadOnly Property View As ICollectionView
        Get
          Return cvs.View
        End Get
      End Property
    
      Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
      Private Sub OnPropChanged(<CallerMemberName> Optional propName As String = "")
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propName))
      End Sub
    
    End Class
    
    Public Class Window32Data
      Public Property Info As String
    End Class


    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks

    Friday, May 17, 2019 7:29 AM