wpf在过程中强制更新UI窗口

时间:2010-09-23 17:22:36

标签: wpf multithreading user-interface refresh

我只需要显示一个自定义控件(带旋转指针的时钟)并用此替换鼠标光标,如果我使用文件.cur或.ani来替换鼠标光标 Me.CUrsor =新光标(“.ani文件的绝对路径”) 没有问题:我可以在程序中更改光标:但动画的质量非常糟糕,而且,出于其他原因,我更喜欢使用我的小用户控件。问题是,如果我写:

Me.gridScreen.Visibility = Visibility.Visible

'一些约需1秒的操作

Me.gridScreen.Visibility = Visibility.Hidden

(gridScreen是包含用户控件的网格)

显然我什么也看不见,因为UI的更新发生在程序的最后。我尝试过Me.UpdateLayout(),但它不起作用。

我试图以多种方式使用调度程序,但没有一个可行: - (

这是我失败的尝试:

(uCurClock是用户控件,gridScreen是一个放置在窗口顶层的网格,背景为trasparent,包含usercontrol)

Private Sub showClock()G
    Dim thread = New System.Threading.Thread(AddressOf showClockIntermediate)
    thread.Start()
End Sub

Private Sub hideClock()
    Dim thread = New System.Threading.Thread(AddressOf hideClockIntermediate)
    thread.Start()
End Sub

Private Sub showClockIntermediate()
    Me.Dispatcher.BeginInvoke(DispatcherPriority.Normal, New Action(AddressOf showClockFinale))
End Sub

Private Sub hideClockIntermediate()
    Me.Dispatcher.BeginInvoke(DispatcherPriority.Normal, New Action(AddressOf hideClockFinale))
End Sub

Private Sub showClockFinale()
    Dim pt As Point = Mouse.GetPosition(Nothing)
    Me.uCurClock.Margin = New Thickness(pt.X - 9, pt.Y - 9, 0, 0)
    Me.gridScreen.Visibility = Visibility.Visible
    Me.Cursor = Cursors.None
    Me.UpdateLayout()
End Sub

Private Sub hideClockFinale()
    Me.gridScreen.Visibility = Visibility.Hidden
    Me.Cursor = Cursors.Arrow
    Me.UpdateLayout()
End Sub

Private Sub u_MouseMove(ByVal sender As System.Object, ByVal e As MouseEventArgs) Handles gridScreen.MouseMove
    Dim pt As Point = e.GetPosition(Nothing)
    Me.uCurClock.Margin = New Thickness(pt.X - 9, pt.Y - 9, 0, 0)

    e.Handled = True
End Sub

Private Sub u_MouseEnter(ByVal sender As System.Object, ByVal e As MouseEventArgs) Handles gridScreen.MouseEnter
    Me.uCurClock.Visibility = Visibility.Visible

    e.Handled = True
End Sub

Private Sub u_MouseLeave(ByVal sender As System.Object, ByVal e As MouseEventArgs) Handles gridScreen.MouseLeave
    Me.uCurClock.Visibility = Visibility.Hidden

    e.Handled = True
End Sub

PIleggi

2 个答案:

答案 0 :(得分:1)

虽然以下代码会按照您的要求执行,但我怀疑它实际上对您没有帮助,因为您已经提到了动画。您将需要使用多个线程。然而,只是为了证明为什么会这样,这里有一些东西可以回答你提出的问题:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles Button1.Click

    uc1.Visibility = Visibility.Visible
    Cursor = Cursors.Wait

    ' Push visibility changes now.
    ' (Sort of like DoEvents - and a horrible idea for exactly the same
    ' reasons that DoEvents was a total train wreck. Never actually do
    ' this - use a background thread instead.)
    Dim df As New DispatcherFrame(True)
    Dispatcher.BeginInvoke(Sub() df.Continue = False, DispatcherPriority.ContextIdle)
    Dispatcher.PushFrame(df)

    Thread.Sleep(1000)

    ClearValue(CursorProperty)
    uc1.Visibility = Visibility.Hidden

End Sub

假设您在页面上有一些名为uc1的用户控件,这将强制它在慢速过程运行时可见。

但是没有动画可以运行。问题是,如果你在UI线程上做的事情很慢,那么UI线程就无法做任何事情 - 它无法运行动画,也无法响应用户输入。 UI基本上被冻结了。这里显示的代码甚至使用户控件可见的唯一原因是它基本上说“现在做任何优秀的UI线程工作”,这会产生将您的更改处理为Visible属性的副作用。

但动画也会在UI线程上发生。

如果要正确执行此操作,则需要在后台线程上进行工作,可能需要使用BackgroundWorker,或者编写自己的线程代码。

答案 1 :(得分:1)

参考DispatcherFrame Class Reference

WPF的好DoEvents !!!

Public Sub DoEvents()
    Dim frame As New DispatcherFrame()
    Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, New DispatcherOperationCallback(AddressOf ExitFrame), frame)
    Dispatcher.PushFrame(frame)
End Sub

Public Function ExitFrame(ByVal f As Object) As Object
    CType(f, DispatcherFrame).Continue = False
    Return Nothing
End Function