Dostęp do kontrolki UI z innych wątków

1

Cześć , problem pewnie stary bo trochę przejrzałem ale u mnie pomimo wdrożenia jakiś sugestii nie działa to tak jak bym chciał . Link całości programu na githubie .

https://github.com/KovalFunky/DirectoryCrawler

Jest klasa która agreguje wszystkie pliki we wskazanym katalogu i podkatalogach . Klasa może pracować jedno lub wielowątkowo w zależności od wybranego trybu i generuje zdarzenie informujące o dodaniu plików do listy .
Jeżeli testuję działanie w aplikacji konsolowej wszystko działa bez zarzutu , w obydwu trybach ..
W przypadku spięcia tego z WF zaczynają się schody . W trybie jednowątkowym aplikacja działa ale nie pokazuje postępu działania enumeratora na bieżąco tylko dopiero jak skończy.
W trybie wielowątkowym po prostu zawisa na zawsze .
Wszystkie opisane klasy poniżej . Ktoś coś gdzieś naprowadzi ...

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace EnumerateAllFiles
{
    public class EnumerateAllFilesClass
    {
        
        private ConcurrentBag<FileInfo> allFileList = new ConcurrentBag<FileInfo>();
        private ConcurrentBag<DirectoryInfo> allDirectories = new ConcurrentBag<DirectoryInfo>();
        private ConcurrentBag<DirectoryInfo> blockDirectories = new ConcurrentBag<DirectoryInfo>();
        private readonly bool _multi;

        private EventManagerLibraryClass EventManager=new EventManagerLibraryClass();
        public event EventHandler<OwnArgsLibraryClass> ReportStatus;
        public event EventHandler<OwnArgsLibraryClass> EndOfProgress;

        public EnumerateAllFilesClass(bool multi=true)  //  konstruktor - multithreading ON - OFF
        {
            _multi = multi;
        } 
        public void Initialize(DirectoryInfo directory)   //  procedura startowa dla całego procesu enumeracji
        {            
            var data = FirstPass(directory);
            AddFilesToList(data.GrabFiles);
            CrawlingDirectories(data.GrabDirectories);
            EventManager.FireEvent(EndOfProgress);
        }

        private void CrawlingDirectories(IEnumerable<DirectoryInfo> grabDirectories)    //  główna procedura rekurencyjna - główna pętla
        {
            if (_multi)
            {
                Parallel.ForEach(grabDirectories, directory =>
                {
                    var data = FirstPass(directory);
                    AddFilesToList(data.GrabFiles);
                    CrawlingDirectories(data.GrabDirectories);

                });
            }
            else
            {
                foreach (var directory in grabDirectories)
                {
                    var data = FirstPass(directory);
                    AddFilesToList(data.GrabFiles);
                    CrawlingDirectories(data.GrabDirectories);
                }
            }


        }
        private (IEnumerable<FileInfo> GrabFiles, IEnumerable<DirectoryInfo> GrabDirectories) FirstPass(DirectoryInfo actualDirectory)  //  pobranie podkatalogów ze wskazanego katalogu
        {
            var ret = GrabFilesFromDirectory(actualDirectory);
            var ret1 = GrabSubDirectories(actualDirectory);
            return (GrabFiles: ret, GrabDirectories: ret1);
        }
        private void AddFilesToList(IEnumerable<FileInfo> grabFiles)    //  dodanie plików do listy końcowych wyników programu
        {
            foreach (FileInfo file in grabFiles)
            {
                allFileList.Add(file);
            }
            EventManager.FireEvent(ReportStatus, new OwnArgsLibraryClass()
            { allFilesCount = allFileList.Count, allDirectoryCount = allDirectories.Count, blockDirectoryCount = blockDirectories.Count });
            
            
        }      

        private IEnumerable<FileInfo> GrabFilesFromDirectory(DirectoryInfo actualDirectory) //  pobranie listy plików ze wskazanego katalogu
        {
            IEnumerable<string> col = null;
            try
            {
                col = Directory.EnumerateFiles(actualDirectory.FullName);
            }
            catch (Exception err)  // nie można pobrać plików z wskazanego katalogu 
            {
                return new List<FileInfo>();
            }            
            var newList = new List<FileInfo>();            
            foreach (var item in col)
            {
                try
                {
                    newList.Add(new FileInfo(item));
                }
                catch (Exception)
                {
                    throw;
                }
            }
            return newList;
        }
        private IEnumerable<DirectoryInfo> GrabSubDirectories (DirectoryInfo actualDirectory)   // pobranie listy podkatalogów ze wskazanej lokalizacji
        {           

            IEnumerable<string> col = null;
            try
            {                
                col = Directory.EnumerateDirectories(actualDirectory.FullName);
                allDirectories.Add(actualDirectory);
            }
            catch (Exception err)  // nie można pobrać plików z wskazanego katalogu 
            {                
                blockDirectories.Add(actualDirectory);  //  dodanie zablokowanego katalogu do listy blokowanych
                return new List<DirectoryInfo>();
            }
            var newList = new List<DirectoryInfo>();
            foreach (var item in col)
            {
                try
                {
                    newList.Add(new DirectoryInfo(item));
                }
                catch (Exception)
                {
                    throw;
                }
            }
            return newList;
        }
    }
}

kod consoli

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using EnumerateAllFiles;

namespace ConsolaTestowa
{
    internal class Program
    {
        static void Main(string[] args)
        {
            var eaf = new EnumerateAllFiles.EnumerateAllFilesClass();
            eaf.ReportStatus += Eaf_ReportStatus;
            eaf.EndOfProgress += Eaf_EndOfProgress;
            eaf.Initialize(new System.IO.DirectoryInfo(@"C:\"));
        }

        private static void Eaf_EndOfProgress(object sender, OwnArgsLibraryClass e)
        {
            Console.WriteLine("KONIEC");Console.ReadKey();
        }

        private static void Eaf_ReportStatus(object sender, OwnArgsLibraryClass e)
        {
            Console.WriteLine(e.allFilesCount);
        }
    }
}

kod WF

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using EnumerateAllFiles;
using static System.Net.Mime.MediaTypeNames;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            EnumerateAllFilesClass ea;

            if ((sender as Button).Name.Contains("Single"))
            {
                ea = new EnumerateAllFilesClass(false);
            }
            else
            {
                ea = new EnumerateAllFilesClass(true);
            }
            
            ea.ReportStatus += Ea_ReportStatus;
            ea.EndOfProgress += Ea_EndOfProgress;
            ea.Initialize(new System.IO.DirectoryInfo(@"C:\"));

        }

        private void Ea_EndOfProgress(object sender, OwnArgsLibraryClass e)
        {
            Update_Label(statusLabel2, "KONIEC");
        }

        private void Ea_ReportStatus(object sender, OwnArgsLibraryClass e)
        {
            var data = new StorageClass() { allFilesCount = e.allFilesCount };
            Update_Label(statusLabel1, data.allFilesCount.ToString());
        }

        private void Update_Label (Label labelToUpdate , string textToUpdate)
        {
            if (labelToUpdate != null)
            {
                if (labelToUpdate.InvokeRequired)
                {
                    Action safeWrite = delegate { labelToUpdate.Text = textToUpdate; };
                    labelToUpdate.Invoke(safeWrite);
                }

                labelToUpdate.Text = textToUpdate;
            }
        }
    }
}

Wyzwalanie zdarzeń

using System;

namespace EnumerateAllFiles
{

    public class EventManagerLibraryClass
    {
        internal void FireEvent(EventHandler<OwnArgsLibraryClass> MyEvent, OwnArgsLibraryClass ownArgs=null)
        {
            if (ownArgs == null) { ownArgs = new OwnArgsLibraryClass(); }

            MyEvent?.Invoke(this, ownArgs);
        }
    }
}
1

Niekomfortowo się czuję z klasami XxxxYyyyClass
Uciekłeś od prawdziwego rzeczownika (*Class jest łatką zamiast tego)

Dla mnie to relatywnie ważne, bo złe / niejasne / nadmiernie otwarte, z gumy nazwy przynoszą złe / niejasne myślenie projektowe

0
vitto239 napisał(a):
>         private void button1_Click(object sender, EventArgs e)
>         {
>             EnumerateAllFilesClass ea;
> 
>             if ((sender as Button).Name.Contains("Single"))
>       

Podrzucę ci skladową sender.Tag (czy button.Tag), która pozwala coś przechowac "w" kontrolce i uniknąć ifóe, kontenerów itd
A uzależnianie od nazwy to mocno amatorskie

(nie mam przy sobie IDE)

1 użytkowników online, w tym zalogowanych: 0, gości: 1