8

我在“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 位图中缺少的 VisualBrushes 的那些。

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

有人对此有解决办法吗?

4

2 回答 2

14

你有两个问题:

  1. 您没有在视觉对象上设置 PresentationSource,因此不会触发 Loaded 事件。
  2. 您没有刷新 Dispatcher 队列。如果不刷新 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可能相关的唯一方法是它是否选择了错误的资源,因为两个资源具有相同的键。我只是想我应该解释一下——这与你的实际问题无关。

于 2010-06-18T22:12:16.960 回答
0

那么内联它,你可以做这样的事情:

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

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

于 2010-05-17T18:23:13.680 回答