2012-09-15 3 views
0

Мои требования:Как заставить RenderTargetBitmap и VisualBrush играть вместе?

  • упорной UserControl, который обрабатывает логику для пользовательского изображения, такие как карта или рисунок
  • набор контейнеров для реализации кэширования на изображение во время масштабирования или панорамирования движений
  • VisualBrush копии UserControl, что я могу добавить к контейнерам для использования с эффектами

я в настоящее время реализовать кэширование изображений с RenderTargetBitmap, но это, кажется, проблема с VisualBrush -накрытых Rectangle объектов, которые я использую.

Мой вопрос: Что я могу добавить/изменить в этом коде, чтобы получить эти VisualBrush объекты для визуализации правильно после RenderTargetBitmap их использует? Какая странная вещь RenderTargetBitmap делает то, что делает VisualBrush невидимым?

Это проблема, которую я не смог воспроизвести без приличного количества кода.

В моем файле XAML у меня есть:

<Window x:Class="ElementRender.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Height="350" Width="525"> 
    <Grid> 
    <Grid Name="_contentContainer"> 
     <Rectangle Fill="White"/> 
     <Grid Name="_content"> 
     <Grid Name="_back"/> 
     <Grid Name="_body"/> 
     </Grid> 
    </Grid> 
    <StackPanel VerticalAlignment="Bottom" Orientation="Horizontal"> 
     <Button Content="New" Name="New"/> 
     <Button Content="Move" Name="Move"/> 
     <Button Content="Update" Name="Update"/> 
    </StackPanel> 
    </Grid> 
</Window> 

и .xaml.cs:

using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Media; 
using System.Windows.Media.Imaging; 
using System.Windows.Shapes; 

public partial class MainWindow : Window 
{ 

    private const int imageWidth = 150; 
    private const int imageHeight = 150; 
    private readonly UserControl Control; 

    public MainWindow() 
    { 
    InitializeComponent(); 

    // User Control setup 
    Control = new UserControl() { 
     Width = imageWidth, Height = imageHeight, 
     Content = BuildImage() 
    }; 
    _body.Children.Add(SoftCopy(Control)); 

    // event setup 
    Move.Click += (sender, e) => _content.RenderTransform = new TranslateTransform(50, 50); 
    New.Click += (sender, e) => { 
     HardCopy(); 
     _content.RenderTransform = null; 
     Control.Content = BuildImage(); 
    }; 
    } 

    private FrameworkElement BuildImage() 
    { 
    return new Rectangle{Fill=Brushes.Blue}; 
    } 
    private void HardCopy() 
    { 
    int width = (int) _contentContainer.ActualWidth; 
    int height = (int) _contentContainer.ActualHeight; 

    // render the current image 
    var rtb = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Pbgra32); 
    DrawingVisual dv = new DrawingVisual(); 
    using (var context = dv.RenderOpen()) 
    { 
     var brush = new VisualBrush(_contentContainer) { Opacity = .5 }; 
     context.DrawRectangle(brush, null, new Rect(0, 0, width, height)); 
    } 
    rtb.Render(dv); 
    var lastRender = new Image 
    { 
     Source = rtb, 
     Stretch = Stretch.None, 
     HorizontalAlignment = HorizontalAlignment.Center, 
     VerticalAlignment = VerticalAlignment.Center, 
     Width = width, 
     Height = height 
    }; 
    _back.Children.Clear(); 
    _back.Children.Add(lastRender); 
    } 
    private FrameworkElement SoftCopy(FrameworkElement element) 
    { 
    return new Rectangle{Fill= new VisualBrush(element), Width=element.Width, Height=element.Height}; 
    } 
} 

Несколько помогают заметки о коде:

  • в XAML в _contentContainer работы с HardCopy(), чтобы скопировать текущие изображения в кэш изображения, _back.
  • SoftCopy возвращает элемент FrameworkElement, который выглядит точно так же, как в прошлом, но без каких-либо преобразований, эффектов или визуальных родителей. Это очень важно.
  • BuildImage имитирует создание нового изображения, которое будет вставлено в кеш после того, как исходное изображение каким-то образом было преобразовано.

Если построить и запустить приложение с удалением SoftCopy() из _body.Children.Add(SoftCopy(Control));, вы видите эффект, который я хочу получить: новый элемент приклеивается над старым элементом, а старый элемент, кажется, сохранить его преобразование.

В качестве альтернативы, если вы вырезали линию var rtb = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Pbgra32); от HardCopy, функция кеширования нарушена, но SoftCopy отображается правильно.

Однако, если вы запустите приложение как есть, вы заметите, что новый BlueRectangle (как визуализируется с помощью VisualBrush) вообще не отображается, пока вы снова не нажмете кнопку «Создать», нажав изображение на кеш и не показывая вам новое созданное изображение.

+0

Вопрос был полностью рассмотрен здесь: http://stackoverflow.com/questions/2851236/rendertargetbitmap-resourced-visualbrush-incomplete-image –

ответ

3

Я собираюсь быть напыщенным, чтобы называть это ошибкой в ​​WPF. В конце концов я узнал, как исправить странное поведение я получал:

var visual = visualBrush.Visual; 
visualBrush.Visual = null; 
visualBrush.Visual = visual; 

Это должен быть по существу нулевой операции: в конце концов, визуальная щетка имеет такое же визуальное, когда она началась. Однако добавление этого сегмента кода после рендеринга VisualBrush в RenderTargetBitmap устраняет проблему, которую я имел.

0

я не совсем понял поста, но есть несколько важных вещей:

Если применить RenderTransform/Поле к элементу и сфотографировать его (RenderTargetBitmap), ты будешь иметь плохое время. Он будет компенсирован, и вы получите только суб-изображение.

Идея состоит в том, чтобы делать снимок без каких-либо rendertransforms, а затем копировать RenderTransform поверх старого. Если нужно.

+0

Я знаю, что это старый пост, но можете ли вы объяснить, что вы подразумеваете под RenderTransform/Поля? Я получаю проблему смещения (слева). Является ли эта ошибка WPF документированной где угодно? – MC9000