我的要求:
- 处理自定义图像逻辑的持久性
UserControl
,例如地图或绘图 - 一组容器,用于在缩放或平移移动期间对图像进行缓存
VisualBrush
UserControl
我可以添加到容器中以与效果一起使用的副本
我目前使用 RenderTargetBitmap 实现图像缓存,但这似乎与我正在使用的VisualBrush
-covered对象有问题。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 呈现)根本不会显示,直到您再次点击“新建”按钮,将图像推送到缓存,并且仍然没有向您显示新创建的图像。