Search code examples
wpfuser-interfacetreeviewbackgroundworker

Failing to update UI after backgroundworker completed


My program at the moment seems to be working up to the point that where the backgroundworker is doing what its supposed to do in that the UI remains responsive while its performing this time consuming task. Although i have not been able to figure out how i should be updating the Treeview, at the moment i have to close the application and open it back up again for the updated Treeview to be visible. I understand that the UI is on a separate thread, and I have tried using dispatcher but no luck...

Dispatcher.BeginInvoke(
DispatcherPriority.Input, new Action(() => 
{ 
    //update UI
}));

This is the TreeView XAML:

<TreeView x:Name="folderView" Grid.Column="0" Grid.Row="1" BorderThickness="0">
            <TreeViewItem Header="Folders" ItemsSource="{Binding SubFolders, Source={StaticResource RootFolderDataProvider}}" Margin="5"/>

            <TreeView.Resources>
                <HierarchicalDataTemplate DataType="{x:Type my:FolderView}" ItemsSource="{Binding SubFolders}">
                    <StackPanel Orientation="Horizontal" Name="myPanel">
                        <Image x:Name="img" Width="16" Height="16" Source="Images/FolderClosed.png" />
                        <TextBlock Text="{Binding Name}" />
                    </StackPanel>

                    <HierarchicalDataTemplate.Triggers>
                        <DataTrigger Binding="{Binding IsExpanded, RelativeSource={RelativeSource AncestorType={x:Type TreeViewItem}}}" Value="True">
                            <Setter TargetName="img" Property="Source" Value="Images/FolderOpen.png"/>
                        </DataTrigger>
                    </HierarchicalDataTemplate.Triggers>
                </HierarchicalDataTemplate>    
            </TreeView.Resources>
        </TreeView>

And this is the Code-Behind for running the DB Update complete with backgroundworker:

       private void cmdUpdate_Click(object sender, RoutedEventArgs e)
    {
            if (backgroundWorker_Database.IsBusy != true)
                {
                    backgroundWorker_Database.RunWorkerAsync(qMaker);
                }
            }
    private void databaseWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker worker = sender as BackgroundWorker;

                 //start the time-consuming process

        }
    }
    private void databaseWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if (e.Error != null)
        {
            //An error was thrown by the DoWork event handler
            MessageBox.Show(e.Error.Message, "An Error Occured");
        }
        else
        {
            MessageBox.Show("Update of Database is Completed!");
        }
        cmdUpdate.IsEnabled = true;
        cmdThumbnails.IsEnabled = true;
        cmdOriginals.IsEnabled = true;
    }

    private void databaseWorker_progressChanged(object sender, ProgressChangedEventArgs e)
    {
        //Update the UI Treeview
    }

And this is the FolderView code complete with PropertyChangedEventHandler:

    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged([CallerMemberName] String propertyName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }


    public ObservableCollection<FolderView> SubFolders
    {
        get
        {
            if (this.subFolders == null)
            {
                this.subFolders = new ObservableCollection<FolderView>();
                //this.subFolders.Clear();

                DirectoryInfo[] di = this.folder.GetDirectories();

                for (int i = 0; i < di.Length; i++)
                {
                    FolderView newFolder = new FolderView();
                    newFolder.FullPath = di[i].FullName;
                    this.subFolders.Add(newFolder);
                }
            }
            return this.subFolders;
        }
        set
        {
            this.subFolders = value; OnPropertyChanged("SubFolders");
        }
    }

Once again, the program threading seems to be working ok in that the UI remains responsive when a time consuming task is being performed. Any help would be appreciated.


Solution

  • I was close with the Dispatcher... This works.

    private void databaseWorker_DoWork(object sender, DoWorkEventArgs e)
    {
            ....
            Dispatcher.BeginInvoke(DispatcherPriority.Input, new Action(() =>
            {
                folderView.Items.Refresh();
                folderView.UpdateLayout();
            }));
            ....
    

    Now the UI is refreshed!