2011-07-24 39 views
1

在以下XAML中,editPanel始终可见。通过按F5键启动长时间操作时,叠加网格仅可见。视觉效果是editPanel变灰将会发生漫长的过程。为什么当TextBox具有焦点时,WPF Grid的可见性会延迟?

<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> 

overlayGrid完全按照预期显示,除非TextBox具有焦点。如果TextBox具有焦点,则在看到overlayGrid快速闪烁之前发生长操作。就好像代码是:做长操作,显示overlayGrid,折叠overlayGrid。

执行长操作,并且改变overlayGrid的能见度如下视图模型代码:

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 

为什么overlayGrid的实际知名度延迟当一个TextBox具有焦点?我该如何解决这个问题?

回答

2

AFAIK,即使在WinForms中也不鼓励使用System.Windows.Forms.Application.DoEvents()。你当然不应该在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 
+0

您的解决方案确实有效。但是在我的“真实”程序中,我有一个绑定到ObservableCollections的多个列表框,这些列表框在长时间的操作中被更新。当然这会由于后台线程而抛出异常。因此我试图使用单线程。 –

+0

@Tim,你永远不应该在UI线程上做任何长操作,因为这会阻塞它。每次修改集合时使用Dispatcher.Invoke(),或缓存更改,然后在完成操作时一次完成所有修改。 – svick

相关问题