【问题标题】:How do I make RenderTargetBitmap and VisualBrush play nice together?如何让 RenderTargetBitmap 和 VisualBrush 一起玩得很好?
【发布时间】:2012-11-02 01:16:22
【问题描述】:

我的要求:

  • 一个持久的UserControl 处理自定义图像的逻辑,例如地图或绘图
  • 一组容器,用于在缩放或平移移动期间对图像进行缓存
  • VisualBrush UserControl 的副本,我可以将其添加到容器中以与效果一起使用

我目前使用 RenderTargetBitmap 实现图像缓存,但这似乎与我正在使用的 VisualBrush-covered Rectangle 对象有问题。

我的问题:在RenderTargetBitmap 使用VisualBrush 对象后,我可以在此代码中添加/更改什么以正确呈现它们? 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 的_contentContainerHardCopy() 配合使用,将当前图像复制到图像缓存_back
  • SoftCopy 返回一个 FrameworkElement,它看起来与过去一模一样,但没有任何变换、效果或视觉父级。这非常重要。
  • BuildImage 模拟在初始图像以某种方式转换后构建要粘贴到缓存上的新图像。

如果您构建并运行从_body.Children.Add(SoftCopy(Control)); 中删除SoftCopy() 的应用程序,您会看到我想要得到的效果:新元素粘贴在旧元素之上,而旧元素似乎保留了它的变换.

或者,如果您从HardCopy 中删除var rtb = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Pbgra32); 行,缓存功能将被破坏,但SoftCopy 会正确显示。

但是,如果您按原样运行应用程序,您会注意到新的 BlueRectangle(通过 VisualBrush 呈现)根本不会显示,直到您再次点击“新建”按钮,将图像推送到缓存,但仍然没有向您显示新创建的图像。

【问题讨论】:

标签: c# .net wpf visualbrush rendertargetbitmap


【解决方案1】:

我会很自负地称其为 WPF 中的错误。我最终发现了如何解决我遇到的奇怪行为:

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

这本质上应该是一个空操作:到最后,视觉画笔具有与开始时相同的视觉效果。但是,在将 VisualBrush 渲染到 RenderTargetBitmap 之后添加此代码段解决了我遇到的问题。

【讨论】:

    【解决方案2】:

    我不太明白这篇文章,但有几件重要的事情:

    如果您将 RenderTransform/Margins 应用于元素并对其进行拍照(RenderTargetBItmap),您将度过一段糟糕的时光。它会被抵消,你只会得到子图片。

    这个想法是在没有任何渲染转换的情况下拍照,然后从旧的 RenderTransform 复制过来。如果需要的话。

    【讨论】:

    • 我知道这是一篇旧帖子,但您能解释一下您所说的 RenderTransform/Margins 是什么意思吗?我也遇到了偏移问题(在左侧)。这个 WPF 错误是否记录在任何地方?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-27
    • 2015-04-30
    • 2011-03-16
    • 2016-11-13
    • 1970-01-01
    • 2014-01-06
    • 2010-09-05
    相关资源
    最近更新 更多