Поднять событие из одного класса и подписаться на другое - PullRequest
0 голосов
/ 13 сентября 2018

Я работаю над проектом, который в основном запускает сканирование и определяет, доступна ли конфиденциальная информация в каталогах на основе определенных регулярных выражений. В этом проекте у нас есть основной проект (WPF), а именно DataScannerUI, и библиотека классов, а именно FileScanCore. FileScanCore ссылается на DataScannerUI.

Краткое описание:

Так работает мой проект. Вся логика, связанная со сканированием, записывается в FileScanCore, и результирующий набор, сгенерированный отсюда, затем передается в DataScannerUI всякий раз, когда это вызывается. Ниже приведена иерархия сканирования: -

  1. Я определяю источник, который нужно сканировать.
  2. Сканирование исходного каталога (от корневого до дочернего: это просто поиск идентификационного номера пути, который необходимо отсканировать.)
  3. Инвентаризация результатов сканирования в базе данных.
  4. Соберите все пути, которые были инвентаризованы из БД.
  5. Выполнить глубокое сканирование на основе пути инвентаря.
  6. Сохранение результатов глубокого сканирования в базе данных.

Теперь то, что происходит здесь, это то, что нет. 4 если размер источника данных меньше 50 КБ, то для его завершения не требуется много времени. Если размер источника данных равен 600 КБ, например затем это займет около 30 минут. Здесь кажется, что пользовательский интерфейс был повешен, так как здесь не отображается статус. Что мне нужно, это показать какой-то статус и сообщить пользователю, сколько ресурсов было загружено до сих пор в процентах. Это было достигнуто в кратчайшие сроки. Теперь я застрял прямо сейчас, и все логики сообщений о состоянии написаны в DataScannerUI, и дело в том, что я не могу ссылаться на DataScannerUI в FileScanCore (проблема циклической зависимости).

Мне нужно передать процент от FileScanCore в DataScannerUI. Чтобы разобраться в этом, я искал в Google и наткнулся на тему ниже.

Я пытался использовать выше, но первые 2 потока не работали для меня, хотя 3-й работал, но это не удовлетворяет мою потребность. Общий фрагмент, в котором мне нужно внести изменения.

FileScanCore

// This method is written in DeepScanner class that implements IScanner
private Queue<string> BuildInventory(FileSystem fs, IList<string> paths, bool includeChildren)
{
    var previousProgressStatus = 0L;
    var totalPathProcessed = 0L;

    var filesToInventory = new Stack<string>();
    var filesToDeepScan = new Queue<string>();

    //files To Inventory logic is written here. 
    {
        ...
        ...
        ...
    }

    // Here we find all directory and files 
    foreach (var c in fs.GetChildren(currentPath))
    {
        // This is where I determine the percentage completed
        var progressStatus = Math.Abs((totalPathProcessed++) * 100 / fs.TotalCount); 
        previousProgressStatus = ((progressStatus == previousProgressStatus) ? previousProgressStatus : progressStatus);

        filesToInventory.Push(c.FullPath);

        // I am looking for something that can trigger from here 
        // and send percentage change to DataScannerUI. 
    }
}

DataScannerUI

// This method is written in Scan class
foreach (var dataSource in _dataSources)
{
    try
    {
        _scanRunSemaphore.WaitAsync(_cancelSource.Token);
        ActiveDataSource = dataSource;
        _status = $"Performing deep scan - {ActiveDataSource.Name}";

        AllDeepScanners[ActiveDataSource.Name] = new DeepScanner(processors, extractor, _fileTypes, Job.Settings.SkipBinaries);
        ActiveScanner = AllDeepScanners[dataSource.Name];
        ActiveFileSystem = UsedFileSystems[ActiveDataSource.Name];

        // This is where I want to subscribe that event.
        // ActiveScanner is a property of type IScanner
        ActiveScanner.ScanAsync(ActiveFileSystem, _cancelSource.Token, _pauseSource.Token).Wait(); // This is where the inventory gets loaded.
        _status = $"Saving deep scan results - {ActiveDataSource.Name}";

        _logger.Debug($"Storing Deep scan results belonged to data source '{dataSource.Name}'");
        dataSource.SaveDeepScanResults(ActiveFileSystem, services);

        _logger.Debug($"Storing Job Last Scanned info belonged to data source '{dataSource.Name}'");
        SaveLastScanned(services, dataSource);        
    }
    // I'm not mentioning catch block 
}

Я не уверен, что то, что я ищу, даже возможно, но стоит попробовать.

Примечание. Если этого недостаточно, пожалуйста, напишите комментарий, я постараюсь сделать его более понятным и понятным.

1 Ответ

0 голосов
/ 13 сентября 2018

Чтобы передать прогресс в ваш пользовательский интерфейс, вы можете добавить событие в свой класс IScanner.Примерно так:

public delegate void ProgressUpdateHandler(object sender, float progress);

interface IScanner
{
  event ProgressUpdateHandler OnProgressUpdate;
  ...
}

Чтобы реализовать это событие в вашем DeepScanner классе:

public class DeepScanner : IScanner
{
  public event ProgressUpdateHandler OnProgressUpdate;
  ...
}

Чтобы вызвать это событие, вы должны сделать следующее в вашей функции BuildInventory:

// Here we find all directory and files 
foreach (var c in fs.GetChildren(currentPath))
{
  var progressStatus = Math.Abs((totalPathProcessed++) * 100 / fs.TotalCount); // This is where I detemine the percentage completed
  previousProgressStatus = ((progressStatus == previousProgressStatus) ? previousProgressStatus : progressStatus);

  filesToInventory.Push(c.FullPath);

  // Send the progress to anyone who is subscribed to this event.
  OnProgressUpdate?.Invoke(this, progressStatus);
}

Чтобы подписаться и обработать эту функцию в своем коде пользовательского интерфейса:

foreach (var dataSource in _dataSources)
{
  try
  {
    _scanRunSemaphore.WaitAsync(_cancelSource.Token);
    ActiveDataSource = dataSource;
    _status = $"Performing deep scan - {ActiveDataSource.Name}";

    AllDeepScanners[ActiveDataSource.Name] = new DeepScanner(processors, extractor, _fileTypes, Job.Settings.SkipBinaries);
    ActiveScanner = AllDeepScanners[dataSource.Name];
    ActiveFileSystem = UsedFileSystems[ActiveDataSource.Name];

    // Subscribe to the progress updates.
    ActiveScanner.OnProgressUpdate += ActiveScanner_OnProgressUpdate;

    ActiveScanner.ScanAsync(ActiveFileSystem, _cancelSource.Token, _pauseSource.Token).Wait(); // This is where the inventory gets loaded.

    // Now unsubscribe to the progress updates.
    ActiveScanner.OnProgressUpdate -= ActiveScanner_OnProgressUpdate;

    _status = $"Saving deep scan results - {ActiveDataSource.Name}";

    _logger.Debug($"Storing Deep scan results belonged to data source '{dataSource.Name}'");
    dataSource.SaveDeepScanResults(ActiveFileSystem, services);

    _logger.Debug($"Storing Job Last Scanned info belonged to data source '{dataSource.Name}'");
    SaveLastScanned(services, dataSource);
  }
  // I'm not mentioning catch block 
}

...
// Handle the progress updates.
private void ActiveScanner_OnProgressUpdate(object sender, float percent)
{
  // Here you can update your UI with the progress.
  // Note, in order to avoid cross-thread exceptions we need to invoke the
  // UI updates since this function will be called on a non-UI thread.
  if (progressLabel.InvokeRequired)
  {
    progressLabel.Invoke(new Action(() => ActiveScanner_OnProgressUpdate(sender, percent)));
  }
  else
  {
    progressLabel.Text = "Progress: " + progress;
  }
}

В качестве примечания вам может потребоваться изменить _scanRunSemaphore.WaitAsync.Я не слежу за тем, что ты делаешь с этим.Кажется, вы можете использовать его нестандартным способом.

...