В настоящее время я работаю над программой, которая преобразует список файлов с .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. Если есть совершенно другой способ сделать это, я открыт для всей критики.
Что вы используете для своего пользовательского интерфейса? Вы используете Winforms или WPF? – CalebB
Я просто использую WinForms для этого. Я могу использовать WPF, если есть лучший или более простой способ сделать это с помощью этого метода, поскольку я только начал его разрабатывать. – SimTrooper
Возможно, вы захотите настроить таймер отправки, чтобы обновить пользовательский интерфейс вместо этого события. Либо это, либо событие не может быть поднято, поэтому вы можете попытаться выполнить изменение прогресса и такое из диспетчера окна: 'this.Dispatcher.Invoke (new Action (() => {" Do work here ""})); это должно поднять эти изменения в пользовательском интерфейсе. – CalebB