如何实现WPF UI的异步更新操作?

2026-05-06 12:021阅读0评论SEO资讯
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计641个文字,预计阅读时间需要3分钟。

如何实现WPF UI的异步更新操作?

这段代码是一个简单的按钮点击事件处理程序,用于禁用按钮500毫秒,然后重新启用它。以下是简化后的版本:

如何实现WPF UI的异步更新操作?

csharpPrivate Sub Button_Click(sender As Button, e As RoutedEventArgs) Handles btn.Click sender.IsEnabled=False Thread.Sleep(500) sender.IsEnabled=TrueEnd Sub

考虑这个例子:

Private Sub Button_Click( sender As Button, e As RoutedEventArgs) Handles btn.Click sender.IsEnabled = False Thread.Sleep(5000) sender.IsEnabled = True End Sub

在我的场景中,Button_Click是VM中的命令委托,而Thread.Sleep是一个长时间运行的过程(大约2-10秒).

我想,当用户调用命令时,它应立即更新禁用按钮的UI,以便用户在运行时无法执行,然后执行该操作,然后,当操作完成时,取消阻止按钮.

我尝试包装中间线,如下所示:

Dispatcher.BeginInvoke(Sub() Thread.Sleep(5000))

但它没有完成这项工作.
最好的方法是什么?

您也可以使用 BackgroundWorker Control来代替创建自己的线程.
通过调用方法“RunWorkerAsync”,可以在另一个线程中调用DoWork事件.

通过从UI线程调用方法“CancelAsync”,您可以将Backgroundworker设置为“Cancellation Pending”(控件的属性“CancellationPending”则为true).在长时间运行的后台线程中,您可以检查该属性(例如,如果您有一个循环:一旦CancellationPending为true,立即退出循环).这是安全中止线程的一个非常好的功能.

除了Backgroundworker之外,您还可以报告线程的进度(例如,在ProgressBar中使用)

例:

Public Class Form1 Private Sub Form1_Load(sender As Object, e As System.EventArgs) Handles Me.Load '** Set to true if you want the ReportProgress Event BackgroundWorker1.WorkerReportsProgress = True BackgroundWorker1.WorkerSupportsCancellation = True End Sub Private Sub BackgroundWorker1_DoWork(sender As System.Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork Dim i As Integer Dim n As Integer = 100 Dim iLastPerc As Integer While Not BackgroundWorker1.CancellationPending AndAlso i < n '** Do your time consuming actions here Threading.Thread.Sleep(500) If Math.Floor((i / n) * 100) > iLastPerc Then '** If the Progress has changed. Report iLastPerc = CInt(Math.Floor((i / n) * 100)) BackgroundWorker1.ReportProgress(iLastPerc) End If i += 1 End While End Sub Private Sub btnStart_Click(sender As System.Object, e As System.EventArgs) Handles btnStart.Click '** Run the Backgroundworker BackgroundWorker1.RunWorkerAsync() End Sub Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged '** Update the ProgressBar ProgressBar1.Value = e.ProgressPercentage End Sub Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted '** Worker is done. Check for Exceptions or evaluate the Result Object if you like End Sub Private Sub btnCancel_Click(sender As System.Object, e As System.EventArgs) Handles btnCancel.Click '** Cancel the worker BackgroundWorker1.CancelAsync() MsgBox("Finished!") End Sub End Class

在提到您的问题时,代码应为:

Private Sub btn_Click(sender As Button, e As RoutedEventArgs) Handles btn.Click sender.IsEnabled = False Using bw As New BackgroundWorker() AddHandler bw.DoWork, Sub(s, ea) Thread.Sleep(5000) AddHandler bw.RunWorkerCompleted, Sub(s, ea) sender.IsEnabled = True bw.RunWorkerAsync() End Using End Sub

本文共计641个文字,预计阅读时间需要3分钟。

如何实现WPF UI的异步更新操作?

这段代码是一个简单的按钮点击事件处理程序,用于禁用按钮500毫秒,然后重新启用它。以下是简化后的版本:

如何实现WPF UI的异步更新操作?

csharpPrivate Sub Button_Click(sender As Button, e As RoutedEventArgs) Handles btn.Click sender.IsEnabled=False Thread.Sleep(500) sender.IsEnabled=TrueEnd Sub

考虑这个例子:

Private Sub Button_Click( sender As Button, e As RoutedEventArgs) Handles btn.Click sender.IsEnabled = False Thread.Sleep(5000) sender.IsEnabled = True End Sub

在我的场景中,Button_Click是VM中的命令委托,而Thread.Sleep是一个长时间运行的过程(大约2-10秒).

我想,当用户调用命令时,它应立即更新禁用按钮的UI,以便用户在运行时无法执行,然后执行该操作,然后,当操作完成时,取消阻止按钮.

我尝试包装中间线,如下所示:

Dispatcher.BeginInvoke(Sub() Thread.Sleep(5000))

但它没有完成这项工作.
最好的方法是什么?

您也可以使用 BackgroundWorker Control来代替创建自己的线程.
通过调用方法“RunWorkerAsync”,可以在另一个线程中调用DoWork事件.

通过从UI线程调用方法“CancelAsync”,您可以将Backgroundworker设置为“Cancellation Pending”(控件的属性“CancellationPending”则为true).在长时间运行的后台线程中,您可以检查该属性(例如,如果您有一个循环:一旦CancellationPending为true,立即退出循环).这是安全中止线程的一个非常好的功能.

除了Backgroundworker之外,您还可以报告线程的进度(例如,在ProgressBar中使用)

例:

Public Class Form1 Private Sub Form1_Load(sender As Object, e As System.EventArgs) Handles Me.Load '** Set to true if you want the ReportProgress Event BackgroundWorker1.WorkerReportsProgress = True BackgroundWorker1.WorkerSupportsCancellation = True End Sub Private Sub BackgroundWorker1_DoWork(sender As System.Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork Dim i As Integer Dim n As Integer = 100 Dim iLastPerc As Integer While Not BackgroundWorker1.CancellationPending AndAlso i < n '** Do your time consuming actions here Threading.Thread.Sleep(500) If Math.Floor((i / n) * 100) > iLastPerc Then '** If the Progress has changed. Report iLastPerc = CInt(Math.Floor((i / n) * 100)) BackgroundWorker1.ReportProgress(iLastPerc) End If i += 1 End While End Sub Private Sub btnStart_Click(sender As System.Object, e As System.EventArgs) Handles btnStart.Click '** Run the Backgroundworker BackgroundWorker1.RunWorkerAsync() End Sub Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged '** Update the ProgressBar ProgressBar1.Value = e.ProgressPercentage End Sub Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted '** Worker is done. Check for Exceptions or evaluate the Result Object if you like End Sub Private Sub btnCancel_Click(sender As System.Object, e As System.EventArgs) Handles btnCancel.Click '** Cancel the worker BackgroundWorker1.CancelAsync() MsgBox("Finished!") End Sub End Class

在提到您的问题时,代码应为:

Private Sub btn_Click(sender As Button, e As RoutedEventArgs) Handles btn.Click sender.IsEnabled = False Using bw As New BackgroundWorker() AddHandler bw.DoWork, Sub(s, ea) Thread.Sleep(5000) AddHandler bw.RunWorkerCompleted, Sub(s, ea) sender.IsEnabled = True bw.RunWorkerAsync() End Using End Sub