通过进度条显示执行进度

时间:2013-11-17 09:04:07

标签: c# .net stored-procedures progress-bar backgroundworker

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

这是我的代码

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,所以我试图寻找替代方案。

请建议。提前谢谢。

5 个答案:

答案 0 :(得分:10)

一个有趣的想法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

我的表格用

  • 一个按钮(CallSpButton
  • 进度条(progress
  • 标签(statusLabel)和
  • 后台工作人员(SpCallerWorkerReportsProgress设为true

Screenshot

最后是拨打电话的代码

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;
    }
}

答案 1 :(得分:7)

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

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

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

也许你想要一些形式(猜测语法,因为我没有编译器可以处理)并借用Windows Forms ProgressBar: Easiest way to start/stop marquee?

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());

答案 2 :(得分:2)

存储过程不提供进度信息。您可以ProgressBar样式设置中使用Marquee ProgressBar.Style PropertyProgressBarStyle.Marquee

答案 3 :(得分:2)

请遵循此方法。

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

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

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

  4. 请同时拨打两个主题 backgroundWorker1.RunWorkerAsync();

    我认为这可以解决您的问题。


答案 4 :(得分:0)

我研究了背景工作者,我这样做 我把我的程序的执行放在另一个线程和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;
        }