【问题标题】:WPF - Updating Elements While Long Operation Is Running In The Background [duplicate]WPF - 在后台运行长时间操作时更新元素[重复]
【发布时间】:2021-02-18 11:12:25
【问题描述】:

我正在构建一个简单的 WPF 应用程序,并且在应用程序的许多地方,我都需要进行长时间的操作,在此期间我想更新 UI,使其看起来不像应用程序崩溃。 例如,我有一个登录按钮,当我按下它时,除了验证所有凭据之外,它还会加载该特定用户数据的二进制数据库。对于拥有大量数据的用户,可能需要大约 3-5 秒,对于另一个可能是即时的。

我想要的是能够在完成 Button Click 事件之前更新其他元素,并且我希望按照代码的确切顺序进行。

这里是登录按钮点击事件:

private void btnLogin_Click(object sender, RoutedEventArgs e) {
            var username = txtUsername.Text;
            var password = pswBox.Password;
            lblLoginStatus.Visibility = Visibility.Visible;
            if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password)) {
                lblLoginStatus.Content = "Both username and password cannot be empty!";
            } else {
                prgLogin.Visibility = Visibility.Visible; //Progress bar that should be visible while the long operation is running.
                var login = Adb.Login(username, password); //Long operation
                prgLogin.Visibility = Visibility.Collapsed; //Upon completion of the operation, hide the progress bar.
                if (!login) {
                    lblLoginStatus.Content = "Wrong Credentials!";
                } else { //This basically exits the login page/window
                    LoginPage.Visibility = Visibility.Collapsed;
                    GeneralPage.Visibility = Visibility.Visible;
                }
            }
        }

如您所见,我没有看任何花哨的动画甚至进度报告。进度条是不确定的,我设置了它的样式,所以它只是以可见性触发器开始和结束。

我的问题是,与我的逻辑相反,在按下按钮后,代码实际上按照与编写时相同的顺序运行,它看起来只是卡住了,在操作结束之前没有更新其他元素,此时登录窗口隐藏起来,让我所有努力创建一个令人愉快的 UI 变得毫无价值。

我尝试过使用:

Dispatcher.CurrentDispatcher.Invoke(/*Whatever element update I want*/);

但是没用,结果还是一样……

我在网上看到了一些类似问题的复杂而冗长的解决方案,我尝试实施它们,即使只是为了测试,我现在搞砸了大约 4 个小时,但无济于事。

就像上面一样,我的应用程序的其余部分充满了以下部分:

progressBar.Visibility = Visibility.Visible;
var operation = AnyLongOperation()
prgLogin.Visibility = Visibility.Collapsed;

因此,我正在寻找一种能够适应整个应用程序的简单解决方案。

【问题讨论】:

  • 从 UI 线程调用 Adb.Login(username, password)(如您在此处所做的那样)将阻塞该线程并因此阻塞 UI。使 Login 方法异步并等待它,或者将其包装在等待的任务中。
  • @Clemens 我试图将它包装在一个任务中,然后使用 Task.WaitAll(Task) 但它仍然卡住了......我认为问题是我需要在事件退出验证,如果我使用异步等待,它在等待时会继续所有其他 UI 操作?
  • 是的。使处理程序方法异步,即private async void btnLogin_Click(object sender, RoutedEventArgs e),然后调用var login = await Task.Run(() => Adb.Login(username, password));
  • @Clemens 我认为你应该先使用var operation = Task.Factory.StartNew(() => Adb.Login(username, password));,然后再使用var login = await operation;,或者它们是否相同?
  • 你只会在特殊情况下使用Task.Factory.StartNew。如前所述,使用 Task.Run。

标签: c# wpf user-interface dispatcher


【解决方案1】:

UI 冻结是因为您的程序在一个线程上运行,Adb.Login 阻塞了主线程,因此 UI 无法更新,您必须将 Login 函数移动到另一个线程并从那里更新进度,this 应该帮助,实现起来并不太复杂,或者只是使登录方法异步

【讨论】:

  • 现在你既不会显式运行线程,也不会使用 BackgroundWorker。异步/等待是要走的路。
猜你喜欢
  • 1970-01-01
  • 2011-11-30
  • 1970-01-01
  • 1970-01-01
  • 2017-10-30
  • 1970-01-01
  • 1970-01-01
  • 2012-01-04
  • 2016-03-23
相关资源
最近更新 更多