我目前正在开发一个将.ps(PostScript)文件列表转换为.png的程序。
最初,这是在一个批处理文件中完成的,一次一个文件。我正在处理使用Ghostscript.NET DLL异步处理这些文件的代码。通过将这些分成任务,我将处理时间从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 :(得分:0)
当您从设计器屏幕拖动它时,是否将BackgroundWorker名称赋予该对象?如果不更改您的代码以使用它给出的相应名称(默认应该是backgroundWorker1)。
或......
尝试将发件人对象转换为DoWork方法中的BackgroundWorker对象,并从那里调用ReportProgress()。
private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker bw = sender as BackgroundWorker;
if (bw != null)
{
bw.ReportProgress(25);
}
}