通过进度条显示执行进度

我有一个愚蠢的问题,但我被卡住了。 我正在执行一个存储过程表单,我的代码过程需要时间,所以为此我显示一个进度条,显示执行的进度,但存储过程执行,没有任何东西,我增加进度条的值。

这是我的代码

void btnYes_Click(object sender, EventArgs e) { if (DialogResult.Yes == MessageBox.Show("Are you sure", "", MessageBoxButtons.YesNo)) { try { dbDataEntities db = new dbDataEntities(); string myquery = "DECLARE @return_value int EXEC @return_value = [dbo].[ssspUpdateMarksOfStudent] SELECT 'Return Value' = @return_value"; //progressbar1.Maximum = 5000; //progressbar1.value = ?; // how could i increment it // db.Database.ExecuteSqlCommand("myquery"); } catch (Exception ex) { MessageBox.Show(ex.Message); } } } 

此外,我尝试通过设置当前执行程序时未增加的当前值来使用秒表

 Stopwatch st = new Stopwatch(); st.Start(); progressbar1.Maximum = 5000; progressbar1.Value = Convert.ToInt16(st.Elapsed.Seconds); //My stored procedure call st.Stop(); 

所以它只能通过使用background worker来完成,还是有其他方法可以做到这一点?

我是编程的新手所以没有使用background worker ,所以我试图找到一个替代方案。

请建议。 提前致谢。

一个有趣的想法SqlConnection提供InfoMessage事件,该事件在服务器执行PRINT命令时触发。 您可以在存储过程的某些部分打印并收听此事件。

 -- do something PRINT '10 PERCENT COMPLETED'; -- do another thing PRINT '20 PERCENT COMPLETED'; ... PRINT '100 PERCENT COMPLETED'; 

除此之外,使用@ hamlet-hakobyan的解决方案。 只是展示一个无限的进度吧。


更新:已更新以包含完整解决方案

首先,我讨厌给出完整的答案。 它会妨碍大脑找到解决方案的能力。 相反,我喜欢将人们推向正确的道路,这样他们就可以走路了。 但无论如何它在这里。 在W7x64SP1和SQL2012下使用VS2012,NET4,MSIL进行测试。

我非常耗时SP。 使用RaisError而不是Print立即发送消息。

 Create Procedure usp_LongProcess As Begin Declare @i Int; Declare @msg VarChar(50); Set @i = 0; while (@i < 100) Begin WaitFor Delay '00:00:02'; Set @i = @i + 10; Set @msg = Convert(VarChar(10), @i) + ' PERCENT COMPLETE'; RaisError(@msg, 1, 1) With NoWait End End 

和我的forms

  • 一个按钮( CallSpButton
  • 进度条( progress
  • 标签( statusLabel )和
  • WorkerReportsProgress设置为true的后台工作程序( SpCaller )。

截图

最后是拨打电话的代码

 private void CallSpButton_Click(object sender, EventArgs e) { CallSpButton.Enabled = false; SpCaller.RunWorkerAsync(); } private void SpCaller_DoWork(object sender, DoWorkEventArgs e) { var self = (BackgroundWorker) sender; var cb = new SqlConnectionStringBuilder { DataSource = ".", InitialCatalog = "Sandbox", IntegratedSecurity = true }; using (var cn = new SqlConnection(cb.ToString())) { cn.FireInfoMessageEventOnUserErrors = true; cn.Open(); cn.InfoMessage += (o, args) => self.ReportProgress(0, args.Message); using (var cmd = cn.CreateCommand()) { cmd.CommandText = "usp_LongProcess"; cmd.CommandType = CommandType.StoredProcedure; cmd.ExecuteNonQuery(); } } } private void SpCaller_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { CallSpButton.Enabled = true; } private void SpCaller_ProgressChanged(object sender, ProgressChangedEventArgs e) { var message = Convert.ToString(e.UserState); Debug.WriteLine(message); statusLabel.Text = message; if (message.EndsWith(" PERCENT COMPLETE")) { int percent; if (int.TryParse(message.Split(' ')[0], out percent)) progress.Value = percent; } } 

看起来你正在gui线程上运行存储过程。

这意味着当呼叫正在运行时,您的应用程序将无响应,因为消息泵被阻止。 这可能是一个坏主意。 我建议将所有长时间运行的调用移动到另一个线程。

后台工作程序是一个旨在执行此操作的类,允许您报告长时间运行的任务是如何进行的,以便您可以更新UI,但由于您的任务只是一个项目,因此没有太多要报告的内容,因此它可能不是你的正确选择。

也许你想要一些forms(猜测语法,因为我没有编译器可以处理)并借用Windows Forms ProgressBar:最简单的方法来启动/停止选框?

 progressbar1.Style = ProgressBarStyle.Marquee; //thanks Hamlet progressbar1.MarqueeAnimationSpeed = 30; //run the long running thing on a background thread. var bgTask = Task.Factory.StartNew(() => db.Database.ExecuteSqlCommand("myquery")); //when it's done, back on this thread, let me know and we'll turn the progress bar off bgTask.ContinueWith(resultTask => { progressBar1.Style = ProgressBarStyle.Continuous; progressBar1.MarqueeAnimationSpeed = 0; }, TaskScheduler.FromCurrentSynchronizationContext()); 

存储过程不提供进度信息。 您可以在Marquee样式中使用ProgressBar将ProgressBar.Style属性设置为ProgressBarStyle.Marquee

请按照这种方法。

  1. 首先计算执行存储过程的时间。 db.Database.ExecuteSqlCommand("myquery"); 在此处输入代码

  2. 为执行此查询分配一个单独的线程/(进程的一部分)。 通过在c#中使用后台工作程序控件(在do_work事件中)

  3. 类似地,使用后台工作程序分配一个单独的进程线程来显示进度条状态。( 在Progress-Changed Event中 )只增加10%的值。 给一些小睡眠( 基于消耗你的查询的时间分为十个部分 )。 完成后,使Progressbar.value = 100( 在Run-Worker-CompletedEvent中

请在backgroundWorker1.RunWorkerAsync();同时调用这两个线程backgroundWorker1.RunWorkerAsync();

我认为这解决了你的问题。


我研究了背景工作者,我这样做,我把我的程序执行在另一个线程和GUI线程的进度条

  BackgroundWorker bg = new BackgroundWorker(); Boolean stopwork = true; Private void btnYes_Click(object sender, EventArgs e) { if (DialogResult.Yes == MessageBox.Show(clsGlobalObjectRefrances.OMessageString.SureWant2UpdateMarks, "", MessageBoxButtons.YesNo)) { try { bg.DoWork += bg_DoWork; bg.RunWorkerCompleted += bg_RunWorkerCompleted; bg.RunWorkerAsync(); pgbUpdateMarks.Maximum = 60; Stopwatch st = new Stopwatch(); st.Start(); while(stopwork) { pgbUpdateMarks.Value = st.Elapsed.Seconds; } pgbUpdateMarks.Value = 0; MessageBox.Show("Executed sucessfully"); } catch (Exception ex) { MessageBox.Show(ex.Message); } } } 

DoWork在哪里

  void bg_DoWork(object sender, DoWorkEventArgs e) { dbDataEntities db = new dbDataEntities(); string myquery = "DECLARE @return_value int EXEC @return_value = [dbo].[ssspUpdateMarksOfStudent] SELECT 'Return Value' = @return_value"; db.Database.ExecuteSqlCommand("myquery"); stopwork = false; }