在关闭窗体之前停止一个线程。

3
使用.NET4和c#,我在一个Windows表单上有一个网格。当我点击处理按钮时,我需要对每一行执行几个步骤的及时操作,然后更新该行的结果。这样用户就可以在下一行正在处理时看到进度。如果用户点击取消或关闭表单,则需要完成当前行的处理,然后中断或关闭表单。根据我的研究,这是我得出的结论。我还剩下两个问题。
以下是我的代码:
delegate void OperateGridMethodDelegate();
delegate void UpdateProgressDelegate(int rowIndex, string msg);
bool isCancelled = false;


private void ButtonOne_Click(object sender, EventArgs e)
{
    isCancelled=false;
    OperateGridMethodDelegate delegate = new OperateGridMethodDelegate(LongProcess);`
    delegate.BeginInvoke(null,null);

}

private void ButtonTow_Click(object sender, EventArgs e)
{

    MyButtonOne.Enabled=false;
    isCancelled=true;

}

private void LongProcess()
{

    foreach (DataRow row in dataTableOne.Rows)
    {
        //Do Lengthy Process

        DisplayResult( rowIndex, "this is result of operation" );
        if(isCancelled)
        {
            MyButtonOne.Enabled=true;
            break;

        }

    }

}

private void DisplayResult(int rowIndex,string message)
{

    if(myGrid.InvokeRequired == false)
    {

        myGrid.Rows[rowIndex].value = message;

    }

    else
    {

        UpdateProgressDelegate delegate = new  UpdateProgressDelegate(DisplayResult);
        myGrid.BeginInvoke(delegate, new object[] { rowIndex, message });

    }

}

我还剩下两个问题:
1. 当表格关闭时,我想等待被 OperateGridMethodDelegate 调用的 LongProcess 完成当前的行操作,然后取消操作(就像我使用 ButtonTwo 时一样),但我无法让它起作用。
2. 当调试时,我注意到了一个奇怪的行为,我不确定这是否是错误或正确的,当一行处理完毕时,结果没有设置。相反,下一行会被处理,然后显示前一行的结果。第二行的结果在第三行完成后显示,以此类推。然后最后两行结果基本同时显示。
我的做法正确吗?

3
不要使用委托的BeginInvoke()方法来实现线程,bool类型不是同步原语。有更好的方法来处理这个问题,如何正确处理BackgroundWorker的线程问题在此问答中有涵盖:链接 - Hans Passant
1个回答

3
如果你在一个线程中启动了某个任务,在继续之前等待它完成,可以这样做:
yourThread.Join();

这将阻塞直到线程退出。你可能希望在Form_Closing事件中使用类似这样的代码。

另外,如果你想让应用程序被终止时自动终止线程,你需要设置线程的background属性:

yourThread.IsBackground = true;

这意味着它是您主线程的后台线程,因此它将随着主线程一起结束。
编辑:
使用自己的线程:
private Thread yourThread = new Thread(() = > LongProcess());
yourThread.IsBackground = true;
yourThread.Start();  // This will begin your 'LongProcess' function.

现在,如果您想阻塞某个位置并等待其完成,可以执行我先前提到的操作:yourThread.Join(); 此外,请注意,如果将IsBackground = false,并且有人关闭应用程序,则该线程将不会立即退出,尽管UI窗口已关闭,它仍将继续直到完成。

你的Thread是什么?我在哪里可以找到它?我不太明白。 - Mike Turner
一般来说,我不会像你这样做,但考虑到你想要对长时间运行的任务进行控制,使用自己的“Thread”绝对是明智的选择。你可以在声明delegate void的地方声明线程,并在“ButtonOne_Click”事件中调用.Start()方法启动线程。 - pay
我不确定你在那个方法里在做什么。不过,无论你在做什么,我会简化它。你只是更新一个UI元素吗? - pay
我正在更新一个UI元素,但根据.NET规则,您只能通过创建控件的线程来更新UI元素。 - Mike Turner
是的,这就是Dispatcher类的作用。 - pay
显示剩余9条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接