为什么在TextBox具有焦点时,WPF网格的可见性会延迟?

时间:2011-07-24 10:33:42

标签: wpf vb.net grid visibility

在以下XAML中,editPanel始终可见。只有在按F5键启动长操作时,overlayGrid才可见。 editPanel灰显的视觉效果将导致长时间的过程。

<Window.InputBindings>
    <KeyBinding Key="F5" Command="{Binding Path=RefreshCommand}"/>
</Window.InputBindings>

<Grid>

    <StackPanel Name="editPanel">
        <TextBox>set focus here to see the problem.</TextBox>
        <CheckBox>set focus here to remove the problem.</CheckBox>
        <TextBlock Text="{Binding Path=Worker.Message}"/>
    </StackPanel>

    <Grid Name="overlayGrid" 
          Visibility="{Binding Path=Worker.Visibility}"
          Background="Gray" Opacity="0.5">

        <TextBox Text="{Binding Path=Worker.Message}" FontWeight="Bold" 
                 HorizontalAlignment="Center" VerticalAlignment="Center" 
                 />

    </Grid>

</Grid>

除了TextBox具有焦点外,overlayGrid完全按预期显示。如果TextBox具有焦点,则在看到overlayGrid的快速闪烁之前会进行长时间操作。就好像代码是:做长操作,显示overlayGrid,折叠overlayGrid。

执行long操作并更改overlayGrid可见性的ViewModel代码如下:

Sub Refresh()

    Me.Worker.Message = String.Format("Refresh started at {0}..", 
                                      Date.Now.ToString("hh:mm:ss.fff")
    )

    Me.Worker.Visibility = Visibility.Visible

    ' Give the UI a chance to update itself.
    System.Windows.Forms.Application.DoEvents()

    Console.WriteLine("Debug: " + Me.Worker.Message)

    ' Fake the long operation.
    System.Threading.Thread.Sleep(1000)

    Me.Worker.Message = String.Format("Refresh completed at {0}.", 
                                      Date.Now.ToString("hh:mm:ss.fff")
    )

    Me.Worker.Visibility = Visibility.Collapsed

    Console.WriteLine("Debug: " + Me.Worker.Message)

End Sub

为什么在TextBox具有焦点时,overlayGrid的实际可见性会延迟?我该如何解决这个问题?

1 个答案:

答案 0 :(得分:2)

即使在WinForms中,也不鼓励使用System.Windows.Forms.Application.DoEvents()的AFAIK。你肯定不应该在WPF中使用它,即使它有效(显然,它没有)。

您应该做的是在后台线程上运行长操作,然后使用Dispatcher.Invoke()在UI上设置结果。类似的东西:

Sub Refresh()

    Me.Worker.Message = String.Format("Refresh started at {0}..",
                                      Date.Now.ToString("hh:mm:ss.fff")
    )

    Me.Worker.Visibility = Visibility.Visible

    Console.WriteLine("Debug: " + Me.Worker.Message)

    Task.Factory.StartNew(
        Function()
            ' Fake the long operation.
            System.Threading.Thread.Sleep(10000)

            Dispatcher.Invoke(
                Function()
                    Me.Worker.Message = String.Format("Refresh completed at {0}.",
                                                      Date.Now.ToString("hh:mm:ss.fff")
                    )

                    Me.Worker.Visibility = Visibility.Collapsed

                    Console.WriteLine("Debug: " + Me.Worker.Message)

                End Function)

        End Function)

End Sub