如何在WinForms C#中使用线程?

如何在WinForms C#中使用线程?,c#,multithreading,winforms,C#,Multithreading,Winforms,我有一个关于使用线程的问题。我有一个WinForms应用程序。我有一个带有方法的开始按钮。当我点击它时,该方法开始执行并持续很长时间。当该方法正在执行时,表单处于非活动状态,我甚至无法关闭它,直到该方法结束。我想激活表单并单击另一个按钮(停止按钮)停止方法的执行 private void start_Click(object sender, EventArgs e) { StartLoading() //Some Method which performing I

我有一个关于使用线程的问题。我有一个WinForms应用程序。我有一个带有方法的开始按钮。当我点击它时,该方法开始执行并持续很长时间。当该方法正在执行时,表单处于非活动状态,我甚至无法关闭它,直到该方法结束。我想激活表单并单击另一个按钮(停止按钮)停止方法的执行

    private void start_Click(object sender, EventArgs e)
    {
        StartLoading() //Some Method which performing I want to stop at any time
    }

    private void stop_Click(object sender, EventArgs e)
    {
        //Stop performing Method from start_Click
    }
我尝试使用下一个代码:

    private void start_Click(object sender, EventArgs e)
    {
        Thread StartThread = new Thread(StartLoading);
        StartThread.Start();
    }

    public void StartLoading() 
    {
    }
它是有效的。当窗体保持活动状态时,该方法正在执行。但我不知道如何在stop_Click事件中停止此线程。 也许还有别的方法可以做我想做的事

致意
Sergey

如果您在线程内执行一些循环,我建议您添加一个变量,如下所示:

Thread StartThread = null;
private void start_Click(object sender, EventArgs e)
{
    StartThread = new Thread(StartLoading);
    StartThread.Start();
}

public void StartLoading() 
{
    StartThread.Abort();
}
在“停止”按钮中,添加以下内容:

bool isStopped = false;
在你的循环中:

while(yourCondition)
{
    if(isStopped)
       break;
}
这样,它更安全,可以确保您完成当前循环

但是如果你想立即终止它,有一个函数叫做

您必须修改如下代码:

Thread StartThread = null;
private void start_Click(object sender, EventArgs e)
{
    StartThread = new Thread(StartLoading);
    StartThread.Start();
}

public void StartLoading() 
{
    StartThread.Abort();
}

如果希望执行缓慢的操作直到完成或手动取消它,则可能需要使用
Task
CancellationToken
。对我来说,这似乎是最合适的方式:

public class MyForm
{
    private CancellationTokenSource cts = new CancellationTokenSource();
    private Task task;

    private void buttonStart_Click(object sender, EventArgs e) 
    {
        buttonStart.Enabled = false;
        buttonCancel.Enabled = true;

        task = Task.Factory.StartNew(() => {
            // do something extremely slow
            // and use 'ThrowIfCancellationRequested'

            for (int i = 0; i < Int32.MaxValue; i++)
            {
                Thread.Sleep(10);
                cts.Token.ThrowIfCancellationRequested();
            }
        }, cts.Token).ContinueWith(t => {
            if (t.IsCanceled)
            {
                // User has cancelled loading
            }
            if (t.IsFaulted)
            {
                // Exception has occured during loading
            }
            if (t.IsCompleted)
            {
                // Loading complete
            }
        });
    }       

    private void buttonCancel_Click(object sender, EventArgs e)
    {
        buttonStart.Enabled = true;
        buttonCancel.Enabled = false;

        cts.Cancel();
    }
}
公共类MyForm
{
私有CancellationTokenSource cts=新的CancellationTokenSource();
私人任务;
私有无效按钮开始单击(对象发送者,事件参数e)
{
buttonStart.Enabled=false;
按钮取消启用=真;
task=task.Factory.StartNew(()=>{
//做一些非常慢的事情
//并使用“ThrowIfCancellationRequested”
对于(inti=0;i{
如果(t.IsCanceled)
{
//用户已取消加载
}
如果(t.IsFaulted)
{
//加载期间发生异常
}
如果(t.已完成)
{
//装载完成
}
});
}       
私有无效按钮取消单击(对象发送者,事件参数e)
{
buttonStart.Enabled=true;
按钮取消启用=错误;
cts.Cancel();
}
}

您可以为此使用
后台工作人员

        private BackgroundWorker bw = new BackgroundWorker();

        public Form()
        {
            InitializeComponent();

            bw.WorkerSupportsCancellation = true;
            bw.DoWork += new DoWorkEventHandler(bw_DoWork);
            bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
        }

        private void start_Click(object sender, EventArgs e)
        {
            if (!bw.IsBusy)
            {
                bw.RunWorkerAsync();
            }
        }
        private void stop_Click(object sender, EventArgs e)
        {
            if (bw.WorkerSupportsCancellation)
            {
                bw.CancelAsync();
            }
        }
        private void bw_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;

            if (worker.CancellationPending)
            {
                e.Cancel = true;
                return;
            }

            StartLoading(); //Some Method which performing I want to stop at any time
        }
        private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Cancelled)
            {
                //"Canceled!";
            }

            else if (e.Error != null)
            {
                //"Error: " + e.Error.Message);
            }

            else
            {
                //"Done!";
            }
        }

请注意,调用
StartThread.Abort()
将引发异常,应捕获该异常。谢谢。你的答案有效。这很简单。所有其他答案对我来说都太难理解了。)@Sergey
Thread.Abort()
,它会让你的程序处于损坏状态。不要这样做。是的,所以我提出了一个解决办法,并告诉op如果他真的需要立即终止线程,那么就使用这个方法。我认为thread.Abort()对我来说很好。因为我很少使用它,而且只有在出现问题并且我想立即停止程序时,我才考虑它的可操作性。谢谢StartThread.Abort();我认为您需要使用
cts.Token.ThrowIfCancellationRequested()
而不是
if(cts.IsCancellationRequested)返回t.IsCanceled
在任务启动后取消,则返回true。如果您不认为任务认为取消是请求的,但方法完成了它的工作,因此它将其标记为
IsCompleted
@ScottChamberlain当然,您是对的。我已经编辑了我的答案。我是否缺少
尝试。。在某个地方捕获
,或者它会正确处理
操作取消异常
本身吗?谢谢。如果OperationCanceledException与作为第二个参数传递给
StartNew
的同一个令牌相关联,它将被视为特例,并进入IsCanceled状态,而不是IsFaulted状态。如果引发OperationCanceledException,但它未与传入的令牌关联,则它将显示为故障任务。有关详细示例,请参阅MSDN页“”。