当前位置: 首页 > 知识库问答 >
问题:

在继续之前等待结果并且不阻塞UI[重复]

向杜吟
2023-03-14

我有一个textbox和一个TextChanged事件,如果textbox的文本表示现有文件,则调用自定义事件。在这种情况下,会调用外部dll对文件进行一些处理,这可能需要一分钟以上的时间才能完成。我还做了一些后期处理,这取决于此方法返回给我的结果。目前,这是阻塞我的用户界面,这是非常不希望的。

我看到的基本上有两个“选项”/场景。

    null
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        comboBox1.Items.Add("Select One...");
        comboBox1.Items.Add("Item 1");
        comboBox1.Items.Add("Item 2");

        Value = 0;
    }

    public string SetMessage
    {
        set
        {
            if (lblInfo.InvokeRequired)
                lblInfo.BeginInvoke((MethodInvoker)delegate () { lblInfo.Text = Important ? value + "!" : value; });
            else
                lblInfo.Text = Important ? value + "!" : value;
        }
    }

    public bool Important
    {
        get
        {
            return chkImportant.Checked;
        }
        set
        {
            if (chkImportant.InvokeRequired)
                chkImportant.BeginInvoke((MethodInvoker) delegate() { chkImportant.Checked = value; });
            else
                chkImportant.Checked = value;
        }
    }

    public SomeValue Value
    {
        get
        {
            if (comboBox1.InvokeRequired)
            {
                SomeValue v = (SomeValue)comboBox1.Invoke(new Func<SomeValue>(() => SomeValue.Bar));
                return v;
            }
            else
            {
                switch (comboBox1.SelectedIndex)
                {
                    case 1:
                        return SomeValue.Foo;
                    case 2:
                        return SomeValue.Bar;
                    default:
                        return SomeValue.Nothing;
                }
            }
        }
        set
        {
            if (comboBox1.InvokeRequired)
            {
                comboBox1.BeginInvoke((MethodInvoker)delegate ()
                {
                   switch (value)
                   {
                       case SomeValue.Nothing:
                           comboBox1.SelectedIndex = 0;
                           break;
                       case SomeValue.Foo:
                           comboBox1.SelectedIndex = 1;
                           break;
                       case SomeValue.Bar:
                           comboBox1.SelectedIndex = 2;
                           break;
                   }
                });
            }
            else
            {
                switch (value)
                {
                    case SomeValue.Nothing:
                        comboBox1.SelectedIndex = 0;
                        break;
                    case SomeValue.Foo:
                        comboBox1.SelectedIndex = 1;
                        break;
                    case SomeValue.Bar:
                        comboBox1.SelectedIndex = 2;
                        break;
                }
            }
        }
    }

    private void CustomEvent(object sender, EventArgs e)
    {
        if (!Important)
            Important = true;

        SetMessage = "Doing some stuff";

        if (Value == SomeValue.Foo)
            Debug.WriteLine("Foo selected");

        //I don't want to continue until a result is returned, 
        //but I don't want to block UI either.
        if (ReturnsTrueEventually())
        {

            Debug.WriteLine("True!");
        }

        Important = false;
        SetMessage = "Finished.";
    }

    public bool ReturnsTrueEventually()
    {
        //Simulates some long running method call in a dll.
        //In reality, I would interpret an integer and return 
        //an appropriate T/F value based on it.
        Thread.Sleep(5000);

        return true;
    }

    private void textBox1_TextChanged(object sender, EventArgs e)
    {
        //Do I *need* to multithread the whole thing?
        Task.Run(() => CustomEvent(this, new EventArgs()));
    }
}

public enum SomeValue
{
    Nothing = 0,
    Foo = 100,
    Bar = 200
}

我还意识到我可以简化这些属性中的一些代码,以防止复制。为了给自己演示和调试,我现在暂时不做这个。

以下是我与选项1相关的内容(省略了重复代码和getter/setter,而没有调用它们):

private async void CustomEvent(object sender, EventArgs e)
{
    if (!Important)
        Important = true;

    SetMessage = "Doing some stuff";

    if (Value == SomeValue.Foo)
        Debug.WriteLine("Foo selected");

    //I don't want to continue until a result is returned, 
    //but I don't want to block UI either.
    if (await ReturnsTrueEventually())
    {

        Debug.WriteLine("True!");
    }

    Important = false;
    SetMessage = "Finished.";
}

public async Task<bool> ReturnsTrueEventually()
{
    //Simulates some long running method call in a dll.
    //In reality, I would interpret an integer and 
    //return an appropriate T/F value based on it.
    Thread.Sleep(5000);

    return true;
}

共有1个答案

戚晨
2023-03-14

这基本上就是你想要的。我在这里违反了几个最佳实践,但只是表明它没有那么复杂。需要记住的一点是,用户现在可以连续多次单击此按钮。您可以考虑在处理之前禁用它。也可以执行监视器.tryenter()以确保它尚未运行。

    private async void buttonProcess_Click(object sender, RoutedEventArgs e)
    {
         textBlockStatus.Text = "Processing...";
         bool processed = await Task.Run(() => SlowRunningTask());
    }

    private bool SlowRunningTask()
    {
        Thread.Sleep(5000);
        return true;
    }
 类似资料:
  • 我有一个应用程序,通过点击按钮(该数字被定义)用户创建任务(可调用)做一些计算。我希望任务完成时能够做出反应。使用Future.get()阻止应用程序。有什么方法可以在Callable返回结果时做出反应吗?

  • 我有一个方法,可以为WebView的WebEngine设置一个新的网页,需要等到网页加载完成后才能继续使用当前方法。 基本上我想要: 我尝试过使用ChangeListener(),但它只会在我的方法完成执行后执行。我在谷歌上搜索了许多导致更多挫折感的术语,比如“java非阻塞等待布尔值”。最终,我成功地启动了新线程(以防止应用程序GUI锁定)并使用了倒计时(与Thread.join()相反)。下面

  • 我必须使用axios提出请求,以便获取一些数据,这些数据应该作为道具传递给React组件。下面是我的渲染函数: FateChBoardList是一个异步函数,因此它将返回一个promise。我可以将然后和捕获处理程序附加到返回promise,但在这种情况下,我必须在两个处理程序中放入相同的超文本标记语言代码。还有别的办法吗?

  • 我有一个加载页面,我想在其中对不相关的信息执行两个网络请求(rxjava)。在这两个请求完成之前,我不想进入下一页,即使其中一个或两个都失败了。 > 使用zip将请求绑定在一起。有没有办法不必被迫使用双函数,也不必返回null? 请求A和B有一个。doOnNext和。多恩。如果其中一个返回错误,zip observable是否继续?zip订阅服务器是否也会返回错误? 这是最好的方法吗?

  • 问题内容: 我正在尝试在Node.js / Express中创建一个路由,该路由从两个查询中读取数据,然后基于来自查询的数据来增加计数。由于Node.js是异步的,因此在读取所有数据之前会显示总计。 我创建了一个简单的示例,以达到我目前正在做的事情 我不确定要等到两个功能都完成后才能打印总计,我该做什么。我是否需要创建一个自定义事件发射器来实现这一目标? 问题答案: 拥抱异步性: 或使用Promi

  • 我正在使用Spring Webflux和Spring Boot2,我的场景如下: 在返回之前,我如何将来自流量和正常产品列表的结果连接起来?没有反应控制器是可能的吗? 附言。我不想对从调用1获得的结果调用。block()和CompleteableFuture