当 TextBox 获得焦点时,为什么 WPF 网格的可见性会延迟?

发布于 2024-11-26 07:16:59 字数 1842 浏览 0 评论 0原文

在以下 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 完全按照预期显示。如果文本框具有焦点,则在您看到overlayGrid 快速闪烁之前会发生长时间操作。就好像代码是:执行长时间操作,显示overlayGrid,折叠overlayGrid。

执行长操作并更改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的实际可见性会延迟?我该如何解决这个问题?

In the following XAML the editPanel is always visible. The overlayGrid is only visibile when a long operation has been kicked off by pressing the F5 key. The visual effect being that the editPanel is grayed out will the long process takes place.

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

The overlayGrid displays exactly as expected except when the TextBox has focus. If the TextBox has focus the long operation takes place before you see a quick flicker of the overlayGrid. It's as though the code is: do long operation, show overlayGrid, collapse overlayGrid.

The ViewModel code that performs the long operation and changes the visibility of the overlayGrid is as follows:

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

Why is the actual visibility of overlayGrid delayed when a TextBox has focus? How do I work around this issue?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

爱的故事 2024-12-03 07:16:59

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

AFAIK, using System.Windows.Forms.Application.DoEvents() was discouraged even in WinForms. You certainly shouldn't be using that in WPF, even if it worked (apparently, it doesn't).

What you should do instead is to run the long operation on a background thread and then use Dispatcher.Invoke() to set the result on the UI. Something like:

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文