-1

В настоящее время я работаю над программой, которая преобразует список файлов с .ps (PostScript) в .png.Как сообщить о прогрессе в графическом интерфейсе из списка задач?

Первоначально это было сделано в пакетном файле, по одному файлу за раз. Я работаю над кодом, который использует dll Ghostscript.NET для обработки этих файлов асинхронно. Разделив их на задачи, я сократил время обработки от 30 минут до 6 минут.

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

Я знаю, что достаточно пронизывать, чтобы сорвать себя, поэтому любые предложения по наилучшему способу сделать это очень ценятся. В приведенном ниже коде используется BackgroundWorker, чтобы показать прогресс. Раньше я использовал BGWorker, чтобы показать прогресс, но не для нескольких задач, подобных этому. На самом деле, это моя первая многопоточность без использования BGWorker.

Я чувствую, что BGWorker, вероятно, не то, что мне нужно использовать, но я хотел попытаться взять удар в него сам, прежде чем я попрошу.

Вот код, который я до сих пор:

public partial class ProcessStatusForm : Form 
{ 
    public string[] testList; 
    public string wordPath; 
    public string StatusText; 
    public GhostscriptVersionInfo _gs_version_info; 
    public DirectoryInfo dInfo; 
    public List<Task> tasks; 
    public float NumberOfTasks; 
    public bool PS2PNGRunning; 
    public int ProgressPct; 
    public float dPercent; 
    public decimal decPercent; 

    public ProcessStatusForm(string wordDoc, List<string> runList) 
    { 
     InitializeComponent(); 
     this.wordPath = wordDoc; 
     this.testList = runList.ToArray(); 
     this.StatusText = string.Empty; 
     this._gs_version_info = GhostscriptVersionInfo.GetLastInstalledVersion(GhostscriptLicense.GPL | 
      GhostscriptLicense.AFPL, GhostscriptLicense.GPL); 
     this.dInfo = new DirectoryInfo(SettingsClass.PSFolder); 
     this.PS2PNGRunning = false; 
     this.ProgressPct = 0; 
     this.NumberOfTasks = runList.Count; 
    } 

    private void ProcessStatusForm_Shown(object sender, EventArgs e) 
    { 
     //Spawn tasks for each of the .ps files in the PS_FILES folder 
     tasks = new List<Task>(dInfo.GetFiles("*.ps").Length); 

     //Start the BackgroundWorker 
     this.PS2PNGRunning = true; 
     BackgroundWorker.RunWorkerAsync(); 

     foreach (var file in dInfo.GetFiles("*.ps")) 
     { 
      //Get fileName to pass fo the ConvertPS2PNG 
      string inputFile = file.Name; 

      //Create the Task 
      var task = Task.Factory.StartNew(() => ConvertPS2PNG(inputFile)); 
      tasks.Add(task); 
     } 
     //Wait until all tasks have completed 
     Task.WaitAll(tasks.ToArray()); 
     PS2PNGRunning = false; 
    } 

    private void ConvertPS2PNG(string input) 
    { 
     string output = input.Replace(".ps", "_01.png"); 
     input = SettingsClass.PSFolder + input; 
     output = SettingsClass.PNGFolder + output; 
     GhostscriptProcessor processor = new GhostscriptProcessor(_gs_version_info, true); 
     processor.Process(CreateGSArgs(input, output), new ConsoleStdIO(true, true, true)); 
    } 

    private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e) 
    { 
     ProgressPct = 0; 
     while (PS2PNGRunning) 
     { 
      Thread.Sleep(1000); 
      float TasksCompleted = 0; 
      foreach (var tsk in tasks) 
      { 
       if (tsk.Status == TaskStatus.RanToCompletion) 
       { 
        TasksCompleted++; 
       } 
      } 
      StatusText = TasksCompleted + " of " + NumberOfTasks + " converted..."; 
      dPercent = TasksCompleted/NumberOfTasks; 
      dPercent *= 100; 
      decPercent = (decimal)dPercent; 
      decPercent = Math.Round(decPercent); 
      ProgressPct = (int)decPercent; 
      BackgroundWorker.ReportProgress(ProgressPct); 
     } 
     BackgroundWorker.ReportProgress(100); 
    } 

    private void BackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 
     this.ProgressLabel.Text = this.StatusText; 
     this.progressBar.Style = ProgressBarStyle.Continuous; 
     this.progressBar.Value = e.ProgressPercentage; 
    } 

    public string[] CreateGSArgs(string inPath, string outPath) 
    { 
     List<string> gsArgs = new List<string>(); 

     gsArgs.Add("-dBATCH"); 
     gsArgs.Add("-dNOPAUSE"); 
     gsArgs.Add("-sDEVICE=png16m"); 
     gsArgs.Add("-dQUIET"); 
     gsArgs.Add("-sPAPERSIZE=letter"); 
     gsArgs.Add("-r800"); 
     gsArgs.Add("-sOutputFile=" + outPath); 
     gsArgs.Add(inPath); 

     return gsArgs.ToArray(); 
    } 
} 

Когда я положил перерывы в коде BackgroundWorker_DoWork, кажется, что все выходит хорошо, но когда дело доходит до BackgroundWorker.ReportProgress() , он никогда не попадает в метод BackgroundWorker_ProgressChanged().

По крайней мере, я мог бы жить только с достижением progressBar.Style как шатер, пока он работает, чтобы пользователь мог видеть, что программа работает, но отчет о фактическом прогрессе был бы идеальным.

Как я уже говорил, я не проделал много работы с потоками, и все мои знания по этому вопросу в значительной степени исходят от Google и StackOverflow. Если есть совершенно другой способ сделать это, я открыт для всей критики.

+0

Что вы используете для своего пользовательского интерфейса? Вы используете Winforms или WPF? – CalebB

+0

Я просто использую WinForms для этого. Я могу использовать WPF, если есть лучший или более простой способ сделать это с помощью этого метода, поскольку я только начал его разрабатывать. – SimTrooper

+0

Возможно, вы захотите настроить таймер отправки, чтобы обновить пользовательский интерфейс вместо этого события. Либо это, либо событие не может быть поднято, поэтому вы можете попытаться выполнить изменение прогресса и такое из диспетчера окна: 'this.Dispatcher.Invoke (new Action (() => {" Do work here ""})); это должно поднять эти изменения в пользовательском интерфейсе. – CalebB

ответ

0

Было ли имя BackgroundWorker задано объекту, когда вы перетащили его с экрана дизайнера? Если вы не изменили свой код, чтобы использовать соответствующее имя, оно было дано (по умолчанию должно быть backgroundWorker1).

Или ...

Попробуйте заливку объекта отправителя на объект BackgroundWorker в методе DoWork и вызвать ReportProgress() оттуда.

private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e) 
{ 
    BackgroundWorker bw = sender as BackgroundWorker; 
    if (bw != null) 
    { 
     bw.ReportProgress(25); 
    } 
}