如何在UI线程中立即更新WPF绑定属性?
在UI线程执行命令时实时更新UI(替代DoEvents的方案)
相关问题大多聚焦于如何从非UI/后台线程更新UI,但我的需求恰好相反:在UI线程运行的长时间命令中,有没有办法让UI立即更新? 类似旧的DoEvents功能,希望方案通用以帮助他人。
尝试过的无效方法
简化命令测试ProgressText更新效果,但所有操作完成后仅显示最后一条文本“Progress update 5”,无法依次呈现每一步更新。测试代码如下:
Private Sub MoveOrRenameSongs() System.Threading.Thread.Sleep(2000) ProgressText = "Progress update 1" Application.Current.MainWindow.UpdateLayout() System.Threading.Thread.Sleep(2000) ProgressText = "Progress update 2" Application.Current.MainWindow.UpdateLayout() System.Threading.Thread.Sleep(2000) ProgressText = "Progress update 3" Application.Current.MainWindow.UpdateLayout() System.Threading.Thread.Sleep(2000) ProgressText = "Progress update 4" Application.Current.MainWindow.UpdateLayout() System.Threading.Thread.Sleep(2000) ProgressText = "Progress update 5" Application.Current.MainWindow.UpdateLayout() Dim myWindow As MainWindow = Application.Current.MainWindow System.Threading.Thread.Sleep(2000) ProgressText = "Progress update 1" myWindow.UpdateLayout() System.Threading.Thread.Sleep(2000) ProgressText = "Progress update 2" myWindow.UpdateLayout() System.Threading.Thread.Sleep(2000) ProgressText = "Progress update 3" myWindow.UpdateLayout() System.Threading.Thread.Sleep(2000) ProgressText = "Progress update 4" myWindow.UpdateLayout() System.Threading.Thread.Sleep(2000) ProgressText = "Progress update 5" myWindow.UpdateLayout() End Sub
背景细节
我有一个耗时较长的Command,需要在执行过程中更新进度文本。但命令在UI线程运行时会阻塞UI,导致ProgressText无法实时更新。ProgressText绑定到实现了INotifyPropertyChanged的属性,在即时执行的命令中工作正常:
XAML代码
<StatusBar DockPanel.Dock="Bottom" Height="26"> <StatusBarItem HorizontalAlignment="Left" > <TextBlock Text="{Binding StatusText}" Width="Auto"></TextBlock> </StatusBarItem> <StatusBarItem HorizontalContentAlignment="Stretch"> <TextBlock Text="{Binding ProgressText}"></TextBlock> </StatusBarItem> </StatusBar>
属性代码
Private _progressText As String Public Property ProgressText() As String Get Return _progressText End Get Set(ByVal value As String) _progressText = value RaisePropertyChanged("ProgressText") End Set End Property
尝试过将处理逻辑放到后台线程,但遇到多个问题:
- 可以通过
Dispatcher.Invoke更新ProgressText,但无法打开需要用户输入的窗口(线程需为STA); - 即使将线程设为STA,也无法访问父窗口来设置输入窗口的位置;
- 解决上述问题后,更新绑定列表时UI无法同步,因为原有代码均基于UI线程编写。
因此希望保留在UI线程执行,个人爱好应用不在意UI短暂锁定,但需要看到执行进度。
最终有效方案
使用Async/Await结合Task.Delay,让UI线程获得处理更新的机会,实现进度文本依次显示:
Private Async Function MoveOrRenameSongs() As System.Threading.Tasks.Task System.Threading.Thread.Sleep(1000) ProgressText = "Progress update 1" Await System.Threading.Tasks.Task.Delay(100) System.Threading.Thread.Sleep(1000) ProgressText = "Progress update 2" Await System.Threading.Tasks.Task.Delay(100) System.Threading.Thread.Sleep(1000) ProgressText = "Progress update 3" Await System.Threading.Tasks.Task.Delay(100) System.Threading.Thread.Sleep(1000) ProgressText = "Progress update 4" Await System.Threading.Tasks.Task.Delay(100) System.Threading.Thread.Sleep(1000) ProgressText = "Progress update 5" Await System.Threading.Tasks.Task.Delay(100) End Function
内容的提问来源于stack exchange,提问作者Sandra
相关产品推荐
相关产品推荐

