如何在每次循环更新的标签 [英] How to update a label each time in for loop

查看:74
本文介绍了如何在每次循环更新的标签的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我工作的一个WinForm项目,我有循环在标签。我希望在执行 label.text 语句之后每次显示的标签。但它并不显示每个时间,而是循环完成后显示。



我试图通过使用来实现这一的Thread.Sleep ()。但我不能。请帮帮我。
注: - lblProgress是一个标签



下面是我的编码



 的for(int i = 1; I< = sourceTable.Rows.Count  -  1;我++)
{

串结帐;
结帐= sourceTable.Rows [I]技术领域与所述;串GT;(0);

DEST =新的SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings [本地]的ConnectionString);
dest.Open();
destcmd =新的SqlCommand(结账,DEST);
destcmd.ExecuteNonQuery();
dest.Close();

prcmail();
prcmessagecheck();


lblProgress.Text =Hello World的+我;

Thread.sleep代码(10000);
}


解决方案

当你创建一个WinForm应用程序,它纺成一个新的过程,并创建一个新的线程。对用户界面的任何更新都在同一个线程的流程上进行。这意味着,当你的应用程序在做工作很忙,您的用户界面将被阻止,因为它们是在同一线程上。这意味着,为了实现它是什么你想实现的,你必须做一些额外的工作。



的第一步我们需要做的是创建一个函数为你的日常工作​​(我们可以使用一个匿名函数,但因为你是新的C#,我认为这将是更容易理解,如果我们打破它出来),就像这样:

 私人无效的DoWork()
{
的for(int i = 1; I< = sourceTable.Rows.Count - 1;我++)
{

串结帐;
结帐= sourceTable.Rows [I]技术领域与所述;串GT;(0);

DEST =新的SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings [本地]的ConnectionString);
dest.Open();
destcmd =新的SqlCommand(结账,DEST);
destcmd.ExecuteNonQuery();
dest.Close();

prcmail();
prcmessagecheck();


lblProgress.Text =Hello World的+我;

Thread.sleep代码(1000); //我改变了这种从10000到1000(10秒到1秒)
}
}

接下来,我们需要创建一个新的线程来执行我们的的DoWork()功能。它目前还不清楚什么是触发是做好你的工作,但我要承担其点击一个按钮:

 私人无效的button1_Click(对象发件人,EventArgs五)
{
变种工作=新主题(DoWork的);
work.Start();
}



所以,现在,每当有人按一下按钮,我们将开始一个新的线程在该线程执行我们的的DoWork 功能。新的线程产卵,然后执行被立即返回,并为我们的线程在后台执行我们的GUI现在会实时更新。



别急!我们还有更多的问题之一照顾。问题是,窗口的表格控件不是线程安全的,如果我们尝试更新从另一个线程控制,其他则GUI的线程,我们将得到一个跨线程操作错误。要解决这个的关键是使用 InvokeRequired 调用



首先,我们需要另一种功能,不只是标签更新:

 私人无效SetProgressLabel(INT进展)
{
lblProgress.Text =Hello World的进度+;
}

在表单类中,我们还需要创建一个新的委托:

 公共部分Form1类:表格
{
私人委托无效ProgressCallback(INT进展);

// ..
//你的代码
其余// ​​..
}

最后,修改你的的DoWork()的方法是这样的:

 私人无效的DoWork()
{
的for(int i = 1; I< = sourceTable.Rows.Count - 1;我++)
{

串结帐;
结帐= sourceTable.Rows [I]技术领域与所述;串GT;(0);

DEST =新的SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings [本地]的ConnectionString);
dest.Open();
destcmd =新的SqlCommand(结账,DEST);
destcmd.ExecuteNonQuery();
dest.Close();

prcmail();
prcmessagecheck();


如果(lblProgress.InvokeRequired)
{
lblProgress.Invoke(新ProgressCallback(SetProgressLabel),新的对象[] {I});
}
,否则
{
SetProgressLabel(ⅰ);
}

Thread.sleep代码(1000); //我改变了这种从10000到1000(10秒到1秒)
}
}

这使用标签的(从控制衍生 InvokeRequired 属性,以确定是否调用是必需的。它返回真正。如果它的,我们可以只需拨打我们的 SetProgressLabel()函数像我们通常做的。如果它的真正,我们必须使用调用来调用我们的函数。



恭喜!你只是做你的第一个线程安全的应用程序。



现在,只是作为一个一边注意,您没有正确释放和你的对象处理。我建议你​​改变你的的DoWork()代码是这样的:

 私人无效的DoWork()
{
的for(int i = 1; I< = sourceTable.Rows.Count - 1;我++)
{
串结帐;
结帐= sourceTable.Rows [I]技术领域与所述;串GT;(0);

使用(DEST =新的SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings [本地]的ConnectionString)。)
{
dest.Open();
使用(destcmd =新的SqlCommand(结账,DEST))
{
destcmd.ExecuteNonQuery();
dest.Close();

prcmail();
prcmessagecheck();

如果(lblProgress.InvokeRequired)
{
lblProgress.Invoke(新ProgressCallback(SetProgressLabel),新的对象[] {I});
}
,否则
{
SetProgressLabel(ⅰ);
}

Thread.sleep代码(1000); //我改变了这种从10000到1000(10秒到1秒)
}
}
}
}

由于我包你的的IDisposable 到 块,资源将被自动丢弃,一旦超出范围。


I am working on a WinForm project where I have a label in a for loop. I want to show the label each time after executing the label.text statement. But it doesn't show for every time, rather it shows after for loop is finished.

I tried to achieve this by using Thread.Sleep(). But I can't. Please help me. NOTE :- lblProgress is a Label

Here's my coding.

for (int i = 1; i <= sourceTable.Rows.Count - 1; i++)
{

    string checkout;
    checkout= sourceTable.Rows[i].Field<string>(0);

    dest = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["local"].ConnectionString);
    dest.Open();
    destcmd = new SqlCommand(checkout, dest);
    destcmd.ExecuteNonQuery();
    dest.Close();

    prcmail();
    prcmessagecheck();


    lblProgress.Text = "Hello World"+i;

    Thread.Sleep(10000);
}

解决方案

Whenever you create a WinForm application, it is spun up into a new process and a new thread is created. Any updates to the User Interface are all done on the same thread as your process. This means when your application is doing "busy work", your UI will be blocked because they are on the same thread. What this means is that, in order to achieve what it is you're trying to achieve, you have to do a little extra work.

First step we need to do is create a function for your work routine (we could use an anonymous function, but since you are new to C#, I think it'll be easier to understand if we break it out), like this:

private void DoWork()
{
    for (int i = 1; i <= sourceTable.Rows.Count - 1; i++)
    {

        string checkout;
        checkout= sourceTable.Rows[i].Field<string>(0);

        dest = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["local"].ConnectionString);
        dest.Open();
        destcmd = new SqlCommand(checkout, dest);
        destcmd.ExecuteNonQuery();
        dest.Close();

        prcmail();
        prcmessagecheck();


        lblProgress.Text = "Hello World"+i;

        Thread.Sleep(1000); // I changed this from 10000 to 1000 (10 seconds down to 1 second)
    }
}

Next, we need to create a new thread that executes our DoWork() function. Its unclear what the "trigger" is for doing your work, but I'm going to assume its a button click:

private void button1_click(object sender, EventArgs e)
{
    var work = new Thread(DoWork);
    work.Start();
}

So now, whenever someone click the button, we will start a new thread that executes our DoWork function in that thread. The new thread spawns, then execution is immediate returned and our GUI will now update in real time as our thread is executing in the background.

But wait! We still have one more problem to take care of. The problem is that Window's form controls are not thread safe and if we try to update a control from another thread, other then the GUI's thread, we will get a cross-thread operation error. The key to fixing this is to use InvokeRequired and Invoke.

First, we need to make another function that does just the label update:

private void SetProgressLabel(int progress)
{
    lblProgress.Text = "Hello World" + progress;
}

In your form class, we also need to create a new delegate:

public partial class Form1 : Form
{
    private delegate void ProgressCallback(int progress);

    // ..
    // The rest of your code
    // ..
}

Finally, change your DoWork() method to something like this:

private void DoWork()
{
    for (int i = 1; i <= sourceTable.Rows.Count - 1; i++)
    {

        string checkout;
        checkout= sourceTable.Rows[i].Field<string>(0);

        dest = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["local"].ConnectionString);
        dest.Open();
        destcmd = new SqlCommand(checkout, dest);
        destcmd.ExecuteNonQuery();
        dest.Close();

        prcmail();
        prcmessagecheck();


        if (lblProgress.InvokeRequired)
        {
            lblProgress.Invoke(new ProgressCallback(SetProgressLabel), new object[] { i });
        }
        else
        {
            SetProgressLabel(i);
        }

        Thread.Sleep(1000); // I changed this from 10000 to 1000 (10 seconds down to 1 second)
    }
}

This uses the label's (derived from Control) InvokeRequired property to determine if an Invoke is required. It returns true or false. If its false, we can just call our SetProgressLabel() function like we'd normally do. If its true, we must use Invoke to call our function instead.

Congratulations! You just made your first thread safe application.

Now, just as an aside note, you are not properly releasing and disposing of your objects. I recommend you change your DoWork() code to something like this:

private void DoWork()
{
    for (int i = 1; i <= sourceTable.Rows.Count - 1; i++)
    {
        string checkout;
        checkout = sourceTable.Rows[i].Field<string>(0);

        using (dest = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["local"].ConnectionString))
        {
            dest.Open();
            using (destcmd = new SqlCommand(checkout, dest))
            {
                destcmd.ExecuteNonQuery();
                dest.Close();

                prcmail();
                prcmessagecheck();

                if (lblProgress.InvokeRequired)
                {
                    lblProgress.Invoke(new ProgressCallback(SetProgressLabel), new object[] { i });
                }
                else
                {
                    SetProgressLabel(i);
                }

                Thread.Sleep(1000); // I changed this from 10000 to 1000 (10 seconds down to 1 second)
            }
        }
    }
}

Because I wrapped your IDisposable's into using blocks, the resources will automatically be disposed of once it goes out of scope.

这篇关于如何在每次循环更新的标签的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆