2011-07-24 35 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

相關問題