RenderTargetBitmap + Resource'd VisualBrush = неполное изображение - PullRequest
8 голосов
/ 17 мая 2010

Я нашел новый поворот в вопросе «Визуализация в 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;
}

Работает нормально, за исключением одной вещи, написанной с помощью leeetle ... если мой FrameworkElement имеет VisualBrush, эта кисть не попадает в окончательный рендеринг битовой карты Как то так:

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

Все остальное отображается в растровом изображении, но этот VisualBrush просто не будет отображаться. Очевидные решения Google были предприняты и потерпели неудачу. Даже те, которые специально упоминают VisualBrushes, отсутствующие в растровых изображениях RTB.

У меня есть подлое подозрение, что это может быть вызвано тем, что это Ресурс, и этот ленивый ресурс не встроен. Таким образом, возможное исправление было бы как-то (???) принудительно разрешать все статические ссылки на ресурсы перед рендерингом. Но я абсолютно не знаю, как это сделать.

У кого-нибудь есть исправление для этого?

Ответы [ 2 ]

14 голосов
/ 19 июня 2010

У вас есть две проблемы:

  1. Вы не установили PresentationSource в визуале, поэтому загруженные события не будут срабатывать.
  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 может возможно быть связанным, если он выбрал неправильный ресурс, потому что два ресурса имели один и тот же ключ. Я просто подумал, что должен это объяснить - это никак не связано с вашей реальной проблемой.

0 голосов
/ 17 мая 2010

Ну, чтобы встроить это, вы можете просто сделать что-то вроде этого:

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

Если это не сработает, я думаю, что это должно быть что-то конкретное с экземпляром Visual, который вы используете (и это потребует дополнительного кода для лучшей диагностики).

...