如何设置WPF控件的背景并确保在可见时立即呈现?

时间:2016-10-09 16:59:02

标签: wpf rendering

我有一个WPF应用程序,它截取WindowsFormsHost控件的内容并将其应用于Grid控件的背景。 Grid充当从WindowsFormsHost到其他WPF控件的转换屏幕。这样做是为了产生平滑的过渡效果并避免空间问题。我首先将WinFormsHost控件图像捕获为位图并将其应用于网格背景。然后以编程方式将过渡网格的可见性更改为可见。然后执行不透明度动画以平滑地显示另一个控件。它可以在大约70%到90%的时间内完美运行,具体取决于我测试应用程序的计算机。问题是过渡网格背景的渲染速度不够快或正确。所以偶尔我会看到前一个过渡时的截图,它与过渡时的当前屏幕图像不匹配。

如果我能够以某种方式确保在网格可见之前绘制过渡图像,那么每次都可以使用它。我只是看不出怎么做。应用程序似乎总是等到最后一分钟才能进行任何渲染。

我尝试使用Dispatcher.Invoke()和Dispatcher.BeginInvoke()方法强制渲染。我还试图延迟使用Dispatcher Timer显示网格的时间,但无论在设置背景图像的呼叫和设置可见性之间有多长时间,网格都不会始终更新。我也尝试过像InvalidateVisual()这样的东西没有运气。

在查看涉及WPF的rending和UI线程的问题的许多示例之后,我做了几次尝试来纠正这个问题......

尝试1 - 效果不佳,但尝试使用首先将背景设置为空或黑色的代码行更好:

                TransitionScreen.Visibility = Visibility.Visible
                TransitionScreen.Background = Nothing
                TransitionScreen.Background = New ImageBrush(BitmapToImageSource(GrabScreenshot(ScreenWidth, ScreenHeight)))

                State = "WPFControlMode"
                SwitchState()

尝试2 - 迄今为止的最佳结果。根据计算机工作得很好。增加计数器值不会改善结果。 TransitionScreen的外观将以较大的计数器值延迟,但显示前一个屏幕截图的机会相同(在我的笔记本电脑上大约有5次):

Case "Transition" 
            'Grab Screen Shot and apply to transition screen...'

            TransitionScreen.Visibility = Visibility.Visible
            TransitionScreen.Background = Nothing
            TransitionScreen.Background = New ImageBrush(BitmapToImageSource(GrabScreenshot(ScreenWidth, ScreenHeight)))


End Select


'The following code is inside a loop...'
If State = "Transition" Then
TransitionCounter += 1

        If TransitionCounter = 25 Then
            TransitionCounter = 0

            TransitionScreen.Visibility = Visibility.Visible
            TransitionScreen.Background = Nothing
            TransitionScreen.Background = New ImageBrush(BitmapToImageSource(GrabScreenshot(ScreenWidth, ScreenHeight)))

            State = "WPFControlMode"
            SwitchState()         

        End If

End If

尝试3,4,5,... - 尝试通过Dispatcher强制尝试渲染控件。这些尝试似乎没有帮助,并且经常使问题变得更糟。它们与尝试1和2结合使用。

Case "Transition" 
            'Grab Screen Shot and apply to transition screen...'

            TransitionScreen.Visibility = Visibility.Visible
            TransitionScreen.Background = Nothing
            TransitionScreen.Background = New ImageBrush(BitmapToImageSource(GrabScreenshot(ScreenWidth, ScreenHeight)))

            FlushWindowsMessageQueue()


End Select

'Tried many variations of the following procedure.  Every dispatcher priority with both BeginInvoke and Invoke methods, as well as calling the methods through Application and TransitionScreen objects.' 

Private Sub FlushWindowsMessageQueue()
    Application.Current.Dispatcher.Invoke( _
    New Action(AddressOf DummySub), _
    DispatcherPriority.Background, _
    New Object() {})
End Sub

Private Sub DummySub()
End Sub

还有更多的尝试,但这应该让你知道我尝试了什么。这是一个真正的难题。这是一个相当复杂的项目的最后一个主要问题,此时我几乎投入了转换屏幕。如果你能想到什么,我会非常感激。感谢。

1 个答案:

答案 0 :(得分:0)

我确实想出了解决这个问题的方法。在拍摄截图之前,我会做一个过渡动画。过渡动画产生的分辨率图像低于控件通常显示的分辨率。然后我拍摄可以应用于过渡网格控件的低分辨率图像的屏幕截图,在它变得可见之后,足够快以至于没有闪烁。然后,当我想返回WinFormsHost控件时,我会反过来执行此过程。我的应用程序现在可以无闪烁地工作,并且在我尝试的大多数计算机上运行顺畅。在某些具有大型显示器的计算机上,渲染转换屏幕时有时会有轻微的延迟,但仍然没有闪烁。延迟大约是半秒,我认为它与必须渲染过渡图像的较大区域有关。

此外,以上结合方法/尝试#2进行。与尝试#1组合时仍会出现闪烁。