The problem of using multithreading with a simple WPF application

I am completely unfamiliar with WPF, I created a simple WPF application that lists the entire drive structure (folder, files) in TreeView, since this process takes some time when I tried to use a thread to run the GetFolderTree () method and do not let the user the interface stops responding, but I have to deal with some problems, I created a class called FolderBrowser, where I have all this assembly code for the cumulative structure, inside this class I create a new instance of TreeViewItem that contains Keturah drive at the end is used as a return value to populate the TreeView, is the code:

using System.IO;
using System.Windows.Controls;

namespace WpfApplication  
{
  public class FolderBrowser  
  {  
    private TreeViewItem folderTree;
    private string rootFolder;

    public FolderBrowser(string path)
    {
        rootFolder = path;
        folderTree = new TreeViewItem();
    }

    private void GetFolders(DirectoryInfo di, TreeViewItem tvi)
    {
        foreach (DirectoryInfo dir in di.GetDirectories())
        {
            TreeViewItem tviDir  = new TreeViewItem() { Header = dir.Name };         

            try
            {
                if (dir.GetDirectories().Length > 0)
                    GetFolders(dir, tviDir);

                tvi.Items.Add(tviDir);
                GetFiles(dir, tviDir);
            }
            //catch code here
        }

        if (rootFolder == di.FullName)
        {
            folderTree.Header = di.Name;
            GetFiles(di, folderTree);
        }
    }

    private void GetFiles(DirectoryInfo di, TreeViewItem tvi)
    {
        foreach (FileInfo file in di.GetFiles())
        {
            tvi.Items.Add(file.Name);
        }
    }

    public TreeViewItem GetFolderTree()
    {
        DirectoryInfo di = new DirectoryInfo(rootFolder);
        if (di.Exists)
        {                
            GetFolders(di, folderTree);                                
        }

        return folderTree;
    }
  }
}

How can I create new control instances inside this new thread?

+3
4

, , UI :

System.Windows.Application.Current.Dispatcher.Invoke(new System.Action(() => { /* your UI code here */ }));

"" - /, , .

Edit:

HCL . , , :

Dispatcher .

:

private void RunOnUIThread(Action action)
{
    this.dispatcher.Invoke(action);
}

:

RunOnUIThread(() => { /* UI code */ });

:

RunOnUIThread(() =>
{
  Console.WriteLine("One statement");
  Console.WriteLine("Another statement");
});

, , , .

HCL , - , :)

+1

Merkyn Morgan-Graham (. , ), , -.

BackgroundWorker. , TreeViewItem ( , ) ViewModel ().

BackgroundWorker bgWorker = new BackgroundWorker();
bgWorker.DoWork += (s, e) => {
    // Create here your hierarchy
    // return it via e.Result                
};
bgWorker.RunWorkerCompleted += (s, e) => {
    // Create here your TreeViewItems with the hierarchy from  e.Result                
};
bgWorker.RunWorkerAsync();
+2

, . , .

0

, MVVM (, , view/view-model) . () .

, , ObservableCollection. , RunWorkerCompleted ( ) .

MainWindow.xaml:

<Window
    x:Class="WpfApplication.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApplication">
    <StackPanel>
        <TextBlock Text="Contents:" />
        <TreeView ItemsSource="{Binding BaseDirectory.Contents}">
            <TreeView.Resources>
                <HierarchicalDataTemplate
                      DataType="{x:Type local:FileSystemEntry}"
                      ItemsSource="{Binding Contents}">
                    <TextBlock Text="{Binding Name}" />
                </HierarchicalDataTemplate>
            </TreeView.Resources>
        </TreeView>
    </StackPanel>
</Window>

MainWindowViewModel.cs:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;

namespace WpfApplication
{
    public class MainWindowViewModel
    {
        public MainWindowViewModel()
        {
            this.BaseDirectory = new FileSystemEntry("C:\\");
            this.BaseDirectory.Populate();
        }

        public FileSystemEntry BaseDirectory { get; private set; }
    }

    public class FileSystemEntry
    {
        public FileSystemEntry(string path)
            : this(new DirectoryInfo(path))
        {
        }

        private FileSystemEntry(DirectoryInfo di)
            : this()
        {
            this.Name = di.Name;
            this.directoryInfo = di;
        }

        private FileSystemEntry(FileInfo fi)
            : this()
        {
            this.Name = fi.Name;
            this.directoryInfo = null;
        }

        private FileSystemEntry()
        {
            this.contents = new ObservableCollection<FileSystemEntry>();
            this.Contents = new ReadOnlyObservableCollection<FileSystemEntry>(this.contents);
        }

        public string Name { get; private set; }

        public ReadOnlyObservableCollection<FileSystemEntry> Contents { get; private set; }

        public void Populate()
        {
            var bw = new BackgroundWorker();

            bw.DoWork += (s, e) =>
            {
                var result = new List<FileSystemEntry>();

                if (directoryInfo != null && directoryInfo.Exists)
                {
                    try
                    {
                        foreach (FileInfo file in directoryInfo.GetFiles())
                            result.Add(new FileSystemEntry(file));

                        foreach (DirectoryInfo subDirectory in
                            directoryInfo.GetDirectories())
                        {
                            result.Add(new FileSystemEntry(subDirectory));
                        }
                    }
                    catch (UnauthorizedAccessException)
                    {
                        // Skip
                    }
                }

                System.Threading.Thread.Sleep(2000); // Todo: Just for demo purposes

                e.Result = result;
            };

            bw.RunWorkerCompleted += (s, e) =>
            {
                var newContents = (IEnumerable<FileSystemEntry>)e.Result;

                contents.Clear();
                foreach (FileSystemEntry item in newContents)
                    contents.Add(item);

                foreach (FileSystemEntry subItem in newContents)
                    subItem.Populate();
            };

            bw.RunWorkerAsync();
        }

        private ObservableCollection<FileSystemEntry> contents;
        private DirectoryInfo directoryInfo;
    }
}
0
source

Source: https://habr.com/ru/post/1760412/


All Articles