2010-05-17 12 views
7

¡He encontrado un nuevo giro en la pregunta "Visual to RenderTargetBitmap"!RenderTargetBitmap + Resource'd VisualBrush = imagen incompleta

Estoy renderizando vistas previas de material de WPF para un diseñador. Eso significa que necesito tomar una imagen WPF y presentarla en un mapa de bits sin que se muestre esa imagen. ¿Tienes un método poco agradable de hacer que les gusta ver que aquí va

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; 
} 

funciona bien, excepto por una cosa ... si mi leeetle FrameworkElement tiene una VisualBrush, que el cepillo no terminar en la final mapa de bits renderizado Algo como esto:

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

Todo lo demás hace que el mapa de bits, pero que VisualBrush simplemente no se mostrará. Las soluciones obvias de Google se han intentado y han fallado. Incluso los que específicamente mencionan VisualBrushes falta de RTB'd bitmaps.

Tengo una sospecha furtiva de que esto podría ser causado por el hecho de que es un recurso, y ese recurso perezoso no está en línea. Entonces, una posible solución sería, de alguna manera (???), forzar la resolución de todas las referencias de recursos estáticos antes de renderizar. Pero no tengo absolutamente ninguna idea de cómo hacer eso.

¿Alguien tiene una solución para esto?

Respuesta

13

usted tiene dos problemas:

  1. no configuró un PresentationSource visuales en sus eventos tan cargado no se disparará.
  2. No limpió la cola del distribuidor. Sin descargar la cola de Dispatcher, ninguna funcionalidad que use devolución de llamada de Dispatcher no funcionará.

La causa inmediata de su problema es no lavar la cola Dispatcher, ya que VisualBrush lo usa, pero es probable que se encuentre con el problema PresentationSource antes de tiempo, así que corregiría ambos.

Aquí es cómo lo hago:

// 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 de búsqueda no se retrasa en cualquier circunstancia: Se procesa el momento en que se carga el XAML e inmediatamente reemplazado por el valor recuperado del ResourceDictionary. El único manera StaticResource podría posiblemente estar relacionado es si recogió el recurso incorrecto porque dos recursos tenían la misma clave. Solo pensé que debería explicar esto, no tiene nada que ver con tu problema real.

+0

Bueno, lo leí e intenté enjuagar el despachador, pero eso no ayudó por sí solo. Intentaré agregar el origen de la presentación, lo que no hice. Gracias. – Will

+0

Asegúrese de lavar el despachador en último lugar, después de todos los demás pasos.También noté que estableces la altura y el límite de forma explícita, mientras que yo medía con PositiveInfinity. –

+0

@ray, sí, he estado haciendo eso por un tiempo y luego me di cuenta de que Measure solo necesita saber el máximo, en lugar del real. Lo he estado haciendo con + inf desde que lo aprendí. Intentaremos esto pronto – Will

0

bien a inline ella, usted podría hacer algo como esto:

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

Si eso no funciona, mi conjetura sería que debe ser algo específico con la instancia Visual que está utilizando (y que requerirá más código para un mejor diagnóstico).

+1

No quiero tener que explicarle a la gente "Oye, sé que la miniatura está incompleta. ¿Por qué no continúas y no usas los recursos del pincel kthx?" – Will

Cuestiones relacionadas