2010-05-17 5 views
7

Я нашел новый поворот в вопросе «Visual to RenderTargetBitmap»!RenderTargetBitmap + Resource'd VisualBrush = неполное изображение

Я представляю предварительный просмотр материалов 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'd.

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

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

ответ

13

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

  1. Вы не установили PresentationSource на ваших визуальных так нагруженных событий не будет срабатывать.
  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; 
} 

FYI, StaticResource поиск никогда не задерживается ни при каких обстоятельствах: Он обрабатывается в тот момент, XAML загружается и сразу же заменяется значением, извлеченной из ResourceDictionary. только способ StaticResource может возможно быть связанным, если он взял неправильный ресурс, потому что у двух ресурсов был тот же ключ. Я просто подумал, что должен объяснить это - это не имеет никакого отношения к вашей реальной проблеме.

+0

Ну, я читал и пытался промыть диспетчера, но это само по себе не помогло. Я попробую добавить источник презентации, которого я не делал. Благодарю. – Will

+0

Убедитесь, что вы очистили диспетчера последним, после того, как все остальные шаги выполнены.Также я заметил, что вы задали высоту и с вашей границей явно, тогда как я измерил ее с помощью PositiveInfinity. –

+0

@ray Да, я делал это некоторое время, а затем понял, что для измерения нужно знать только max, а не фактическое. Я делал это с + inf, так как узнал об этом. Попытаемся это скоро. – Will

0

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

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

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

+1

Я не хочу объяснять людям: «Эй, я знаю, что миниатюра не завершена. Почему бы вам не пойти дальше, а не использовать ресурсы кисти kthx». – Will