首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C#:取消BeginInvoke()

C#:取消BeginInvoke()
EN

Stack Overflow用户
提问于 2020-12-17 08:46:35
回答 1查看 83关注 0票数 1

我正在尝试让一个控件执行以下操作:

在第一次单击start时显示文本:每30ms显示一个字符。在第二个按钮上,单击cancel the process并立即显示全文。

这是我通过BeginInvoke()传递给控件的方法:

代码语言:javascript
复制
DBX_Dialogue.running = true;
for (int i = 0; i < line.text.Length; i++)
{
    Text += line.text[i];
    Thread.Sleep(30);
    if (DBX_Dialogue.cancel)
    {
        Text = line.text;
        DBX_Dialogue.running = false;
        break;
    }
}
DBX_Dialogue.running = false;

在主窗口的OnClick()方法中,我这样做:

代码语言:javascript
复制
if (DBX_Dialogue.running)
{
    DBX_Dialogue.cancel = true;
    return;
}
else
{
    DelWrite delWrite = WriteLine;
    DBX_Dialogue.BeginInvoke(delWrite);
}

然而,DBX_Dialogue.cancel从来没有被设置为true,所以我想我的方法实际上并没有异步运行--我做错了什么?

EN

回答 1

Stack Overflow用户

发布于 2020-12-17 09:10:14

简而言之,您正在调用的Control.BeginInvoke()方法将调用UI线程上的委托。一旦委托被调用,在该委托的目标完成执行之前,UI线程将无法执行其他代码。

因此,如果您引用的OnClick()方法被认为是处理该UI线程拥有的控件中的click事件,则该事件处理程序无法执行,因为UI线程在处理委托调用时被卡住了。

还有另一个为任何委托类型定义的BeginInvoke()方法。该线程将对线程池中的委托调用进行排队。可能这就是你要打给他的电话?它看起来像这样:

代码语言:javascript
复制
    delWrite.BeginInvoke();

当然,当您这样做时,您将遇到从线程池线程访问UI对象的问题。然后,您需要在那里使用Control.Invoke(),只针对那些特定的语句。在这个网站上有很多讨论这项技术的问题和答案。

你的问题缺乏很多细节,可以帮助我们其他人理解整个场景并提供更好的建议。事实是,代码的基本结构看起来很可疑,而且几乎可以肯定有一种更好的方法,它不需要调用任何BeginInvoke()方法。但是,如果没有更多的细节,就不可能确切地知道这会是什么样子。您可以查看任务并行库和async/await等内容,以了解协调UI线程异步工作的现代方法。

这里有一个大胆的猜测,关于你正在尝试做的事情的一个替代的,现代的实现会是什么样子:

代码语言:javascript
复制
private CancellationTokenSource tcs;

async Task Run(CancellationToken token)
{
    DBX_Dialogue.running = true;
    try
    {
        for (int i = 0; i < line.text.Length; i++)
        {
            Text += line.text[i];
            await Task.Delay(30, token);
        }
    }
    catch (TaskCancelledException)
    {
        Text = line.text;
    }
    finally
    {
        DBX_Dialogue.running = false;
    }
}

void OnClick(object sender, EventArgs e)
{
    if (DBX_Dialogue.running)
    {
        this.tcs.Cancel();
        this.tcs.Dispose();
        this.tcs = null;
        return;
    }
    else
    {
        this.tcs = new CancellationTokenSource();
        _ = Run(tcs.Token);
    }
}

开始时没有代码示例,所以我没有费心编译上面的代码,更不用说实际测试了。它可能需要一些摆弄才能让它像你想要的那样工作。但这是基本的想法。

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65333189

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档