【问题标题】:RenderTargetBitmap + Resource'd VisualBrush = incomplete imageRenderTargetBitmap + Resource'd VisualBrush = 不完整的图像
【发布时间】:2011-02-20 12:41:51
【问题描述】:

我在“Visual to RenderTargetBitmap”问题上发现了一个新的转折点!

我正在为设计师呈现 WPF 内容的预览。这意味着我需要获取 WPF 视觉对象并将其渲染为位图,而不会显示该视觉对象。有一个不错的小方法可以做到这一点,就像在这里看到它一样

private static BitmapSource CreateBitmapSource(FrameworkElement visual)
{
    Border b = new Border { Width = visual.Width, Height = visual.Height };
    b.BorderBrush = Brushes.Black;
    b.BorderThickness = new Thickness(1);
    b.Background = Brushes.White;
    b.Child = visual;

    b.Measure(new Size(b.Width, b.Height));
    b.Arrange(new Rect(b.DesiredSize));

    RenderTargetBitmap rtb = new RenderTargetBitmap(
                                (int)b.ActualWidth,
                                (int)b.ActualHeight,
                                96,
                                96,
                                PixelFormats.Pbgra32);

    // intermediate step here to ensure any VisualBrushes are rendered properly
    DrawingVisual dv = new DrawingVisual();
    using (var dc = dv.RenderOpen())
    {
        var vb = new VisualBrush(b);
        dc.DrawRectangle(vb, null, new Rect(new Point(), b.DesiredSize));
    }
    rtb.Render(dv);
    return rtb;
}

工作正常,除了一件小事......如果我的 FrameworkElement 有一个 VisualBrush,那个画笔不会出现在最终渲染的位图中。像这样的:

<UserControl.Resources>
    <VisualBrush
        x:Key="LOLgo">
        <VisualBrush.Visual>
            <!-- blah blah -->
<Grid 
    Background="{StaticResource LOLgo}">
<!-- yadda yadda -->

其他所有内容都呈现到位图,但 VisualBrush 不会显示。明显的谷歌解决方案已经尝试过并且失败了。甚至那些特别提到 RTB 位图中缺少的 VisualBrush。

我有一个偷偷摸摸的怀疑,这可能是由于它是一个资源,而这个惰性资源没有被内联。因此,一种可能的解决方法是,以某种方式(???)在渲染之前强制解析所有静态资源引用。但我完全不知道该怎么做。

有人解决这个问题吗?

【问题讨论】:

    标签: wpf visualbrush rendertargetbitmap


    【解决方案1】:

    你有两个问题:

    1. 您没有在视觉对象上设置 PresentationSource,因此 Loaded 事件不会触发。
    2. 您没有刷新调度程序队列。如果不刷新 Dispatcher 队列,任何使用 Dispatcher 回调的功能都将无法工作。

    您的问题的直接原因是未能刷新调度程序队列,因为 VisualBrush 使用它,但您可能很快就会遇到 PresentationSource 问题,所以我会解决这两个问题。

    这是我的做法:

    // Create the container
    var container = new Border
    {
      Child = contentVisual,
      Background = Brushes.White,
      BorderBrush = Brushes.Black,
      BorderThickness = new Thickness(1),
    };
    
    // Measure and arrange the container
    container.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
    container.Arrange(new Rect(container.DesiredSize));
    
    // Temporarily add a PresentationSource if none exists
    using(var temporaryPresentationSource = new HwndSource(new HwndSourceParameters()) { RootVisual = (VisualTreeHelper.GetParent(container)==null ? container : null) })
    {
      // Flush the dispatcher queue
      Dispatcher.Invoke(DispatcherPriority.SystemIdle, new Action(() => { }));
    
      // Render to bitmap
      var rtb = new RenderTargetBitmap((int)b.ActualWidth, (int)b.ActualHeight, 96, 96, PixelFormats.Pbgra32);
      rtb.Render(container);
    
      return rtb;
    }
    

    仅供参考,StaticResource 查找在任何情况下都不会延迟:它在加载 XAML 的那一刻进行处理,并立即替换为从 ResourceDictionary 检索到的值。 唯一 StaticResource 可能可能相关的方式是如果它拾取错误的资源,因为两个资源具有相同的键。我只是想我应该解释一下——这与你的实际问题无关。

    【讨论】:

    • 好吧,我确实阅读并尝试刷新调度程序,但这本身并没有帮助。我会尝试添加演示源,但我没有这样做。谢谢。
    • 确保在完成所有其他步骤之后最后刷新调度程序。我还注意到您明确设置了边框的高度和宽度,而我使用 PositiveInfinity 进行了测量。
    • @ray 是的,我已经这样做了一段时间,然后意识到 Measure 只需要知道最大值,而不是实际值。自从我了解到这一点以来,我一直在使用 +inf 来做这件事。很快就会尝试这个。
    • 看这个(VisualTreeHelper.GetParent(container)==null ? container : null) 如果容器是根返回容器,否则返回null?为什么不返回根目录?
    • 我的代码设计用于处理独立的视觉效果和已经由窗口呈现的视觉效果。所以在我的例子中,如果视觉对象有一个父对象,它已经有一个 PresentationSource。只允许一个。通过为 RootVisual 传递 null,我能够以很少的成本对这两种情况使用单个代码路径。最通用的解决方案是 (PresentationSource.FromVisual(container)!=null ? null : FindVisualTreeRoot(container)) 使用单独的 FindVisualTreeRoot 方法,该方法使用 VisualTreeHelper.GetParent 来查找根,但我的代码足以满足大多数目的。
    【解决方案2】:

    要内联它,你可以这样做:

    <Grid>
        <Grid.Background>
            <VisualBrush>
                <VisualBrush.Visual>
                    <!-- blah blah -->
                </VisualBrush.Visual>
            </VisualBrush>
        </Grid.Background>
    </Grid>
    

    如果这不起作用,我的猜测是它必须与您正在使用的 Visual 实例有关(这需要进一步的代码才能更好地诊断)。

    【讨论】:

    • 我不想和人解释“嘿,我知道缩略图不完整。你为什么不继续,不要使用画笔资源kthx。”
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-12
    • 1970-01-01
    相关资源
    最近更新 更多