我有一个c#表单应用程序,用作UI并执行外部exe。我想进行一个进度条增量,直到外部exe完成执行。所以我有以下代码:
// create thread and Start external process
Thread MyNewThread = new Thread(new ThreadStart(startmodule));
MyNewThread.Start();
do
{
if (progressBar1.Value < 100)
{
progressBar1.Value++;
}
} while (MyNewThread.IsAlive);
label5.Text = "Status: Done";
// startmodule()
void startmodule()
{
ProcessObj = new Process();
ProcessObj.StartInfo.FileName = ApplicationPath;
ProcessObj.StartInfo.Arguments = ApplicationArguments;
ProcessObj.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
ProcessObj.Start();
}
相反,它会立即填满栏并显示“完成”消息,但外部exe(AppPath)仍然在后台运行。
请发布一些我坚持的想法。我不知道什么是错的。谢谢你的时间。
答案 0 :(得分:4)
循环运行得如此之快,在任务实际完成之前达到100%。正在检查循环的条件(正在运行的线程)将在您的任务完成之前成立,但循环导致进度条过早填满。
答案 1 :(得分:4)
你无法做到这一点,你无法猜测这个过程需要多长时间。将ProgressBar.Style属性设置为Marquee。启动该过程时,将Visible属性设置为true。使用Process.Exited事件将其设置为false。像这样:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
progressBar1.Style = ProgressBarStyle.Marquee;
progressBar1.Visible = false;
}
private void ButtonRunProcess_Click(object sender, EventArgs e) {
var ProcessObj = new Process();
ProcessObj.SynchronizingObject = this;
ProcessObj.EnableRaisingEvents = true;
ProcessObj.Exited += new EventHandler(ProcessObj_Exited);
ProcessObj.StartInfo.FileName = @"c:\windows\notepad.exe";
// etc...
ProcessObj.Start();
progressBar1.Visible = true;
}
void ProcessObj_Exited(object sender, EventArgs e) {
progressBar1.Visible = false;
}
}
答案 2 :(得分:1)
要运行进度条,您必须能够量化长时间运行任务的进度。代码中没有任何内容可以尝试量化这一点。
您需要在两个进程之间进行通信才能使此进度条正常工作。换句话说,外部进程需要将消息发送回父应用程序,通知父应用程序进度的度量。现在,这可能很难实现,因此marquee style进度条可能更合适。
答案 3 :(得分:1)
最后,我有一些“自由”时间来测试背景工作者,如上所述。我可以说这是最好的解决方案,它不会冻结用户界面。示例实现如下:
preparemodule()
{
ProcessObj = new Process();
ProcessObj.StartInfo.FileName = ApplicationPath;
ProcessObj.StartInfo.Arguments = ApplicationArguments;
}
void run_Click(object sender, EventArgs e)
{
preparemodule();
backgroundWorker1.RunWorkerAsync(ProcessObj);
}
void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
int i=0;
ProcessObj.Start();
while (checkifexists("notepad", 0) == true)
{
i++;
label5.Text = "Status: notepad running... " + progressBar1.Value.ToString() + "%";
Thread.Sleep(3000);
backgroundWorker1.ReportProgress(i);
if ((backgroundWorker1.CancellationPending == true))
{
e.Cancel = true;
}
}
}
void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (e.ProgressPercentage <= 100)
{
progressBar1.Value = e.ProgressPercentage;
}
}
void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
label5.Text = "Status: Done";
}
void cancel_Click(object sender, EventArgs e)
{
backgroundWorker1.CancelAsync();
}
如你所见,我们甚至可以取消它。通过检查记事本是否正在运行,我们可以增加进度条。别忘了在代码中的某处启用bgWorker的“reportsprogress”和“supportscancellation”属性。我希望它有所帮助。
答案 4 :(得分:0)
首先,@ Tim的回答是正确的。
如果您可以控制外部应用程序,请与主进程通信,告知当前状态并根据这些消息更新进度条。
如果不可能,请尝试估计执行时间并根据执行时间设置进度。如果它始终在同一时间执行同一任务,则此选项有效。
答案 5 :(得分:0)
后台工作线程是为这类事情而设计的。 它有一个事件,您可以在处理某些事情时触发,您可以处理它并更新您的进度条。如其他人所指出的那样,你似乎没有任何进步的衡量标准,只是过了一段时间,所以它并不是你想要的进步的指示,而是某种“我很忙”的动画,如果你使用进步的话你可以得到各种各样的问题,这些问题会让UI男孩疯狂,就像它永远不会达到100%,或者在操作完成之前达到100%,甚至是循环。
因此,如果您可以从线程中指出一些进度,例如,如果您循环遍历X项,则每10%的X触发一次progress事件。使用后台工作线程。 如果你不能不使用进度条踢线程,可以看到一些动画控件。线程完成后,再次使动画不可见。动画的内容和方式取决于你和你的UI男孩。