关于我的应用程序的简要说明:
我正在开发的应用程序就是这样一个贺卡设计器。想象一下,其中有一个背景图像,以及无限数量的“层”(特别是图片),它们保留在背景上,并且可以移动、调整大小、前后移动等……
也可以将特定形状应用于这些图层,如星形、椭圆形等,制作卡片后,可以将其保存为 jpeg 文件。
问题
一切正常,但我检测到当将形状应用于图层时,会生成内存泄漏。
这里是每一层的 UserControl 的代码:
<UserControl>
.....
<Grid x:Name="_myGrid" >
<Border x:Name="im_the_problem" BorderThickness="0" OpacityMask="{Binding Path=MyMask.Data, Converter={StaticResource MaskConverter}}">
<!-- My Image... -->
</Border>
</Grid>
</UserControl>
其中 MaskConverter 代码如下:
public class MaskConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
String maskData = value as String;
if (maskData == null)
return null;
if (maskData == "")
return null;
VisualBrush vb = new VisualBrush();
vb.Visual = XamlReader.Parse(maskData) as Visual;
return vb;
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
}
参数“MyMask.Data”是一个 XAML 路径 (这是我正在应用的形状),我从包含不同形状的文本文件动态加载。
所以,原则是,如果我有名为 *im_the_problem* 的边框,则不会释放内存。如果我评论*im_the_problem*(所以我只有矩形图层/没有形状的图片),一切都会像魅力一样工作,没有内存泄漏。
问题应该出在 OpacityMask + VisualBrush 上。
我做错了什么吗?
或者有一个已知的问题吗?有没有办法以不同的方式做同样的事情(将形状应用于图片..)?
谢谢。
A brief explanation about my app:
the application in which I'm working on is such a greeting cards designer. Imagine something in which there is a background image, and an indefinite number of "layers" (in particular, pictures) that stay over the background and can be moved, resized, moved front and back, etc...
It is also possibile to apply particular shapes to these layers, like a star, an ellipse, .. and after the card is made, it's possibile to save is to jpeg file.
The problem
Everything works correctly, but I detected that when a shape is applied to a layer, a memory leak is generated.
Here is the code of the UserControl of each layer:
<UserControl>
.....
<Grid x:Name="_myGrid" >
<Border x:Name="im_the_problem" BorderThickness="0" OpacityMask="{Binding Path=MyMask.Data, Converter={StaticResource MaskConverter}}">
<!-- My Image... -->
</Border>
</Grid>
</UserControl>
where MaskConverter code is the following:
public class MaskConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
String maskData = value as String;
if (maskData == null)
return null;
if (maskData == "")
return null;
VisualBrush vb = new VisualBrush();
vb.Visual = XamlReader.Parse(maskData) as Visual;
return vb;
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
}
The Parameter "MyMask.Data" is a XAML Path (that is the shape that I'm applying) that I dinamically load from a textfile that contains different shapes.
So, the principle is that if I have the border named *im_the_problem*, the memory is NOT released. If I comment *im_the_problem* (so I'll just have rectangular layers/pictures without shapes) everything work like a charm, without memory leaks.
The problem should be in the OpacityMask + VisualBrush.
Am I doing something wrong?
Or is there a known problem? Is there a way to do the same (apply a shape to a picture..) in a different manner?
Thanks.
发布评论
评论(3)
您也许可以尝试将 MyMask.Data 绑定到实际的 Path.Data,并将 Path.Fill 设置为从图像创建的 ImageBrush?
You might be able to try binding the MyMask.Data to an actual Path.Data, and setting the Path.Fill to an ImageBrush created from the image?
您需要冻结您的 VisualBrush ;)
You need to freeze your VisualBrush ;)
我在
DataGrid
的列模板中遇到了这个问题,其中我使用(作为静态 -资源)到
VisualBrush
(也是静态资源)中,并将其用作矩形
的OpacityMask
。每当重新加载 DataGrid 时,Rectangle
都不会释放对OpacityMask
的VisualBrush
引用,我使用内存分析器工具来揭示所有VisualBrush
对象正在使用大量内存。我不明白为什么或如何发生这种情况 - 但我很高兴我并不孤单(即使大约 6.5 年后我遇到了同样的问题......)。
我的 XAML 是这样的:
我读到设置
IsFrozen = true
(使用此技术完成:https://www.codeproject.com/Tips/72221/Freeze-brushes-directly-in-the-XAML-to-improve-you )将有助于解决画笔的内存问题,但这似乎有完全没有效果。诡异的。我想我应该进行实验,并且我推断如果问题是泄漏
VisualBrush
那么我想知道将它作为StaticResource
是否会扰乱对象引用,所以我改变了它到一个“拥有”的对象,就像这样:这解决了问题!我仍然不知道为什么 - 我想知道这是否是 WPF 中的一个错误?
与此相关的是,我开始意识到使用
VisualBrush
太过分了,因为我只渲染一个简单的Path
-VisualBrush
很昂贵,因为它渲染整个 WPF 视图 - 我还从其他文档了解到,Path
本身对于渲染简单形状来说不是必需的,因为它本身是一个完整的UIElement
和FrameworkElement< /code> - 这是“较重”的类型。
我更改了代码以将路径存储在加载到
DrawingBrush
中的GeometryDrawing
静态资源内的PathGeometry
值中:这样做也使得内存使用量下降,希望性能也下降。
在您的项目中,我发现您没有将路径信息用作资源,但应用了相同的技术:将路径加载到
PathGeometry
(或者更确切地说,StreamGeometry
对象)中,它甚至更快,并且适用于不可变的几何图形)并将其设置为DrawingBrush
的Drawing
。I had this problem in a
DataGrid
's column template where I was using a<Canvas><Path /></Canvas>
(as a static-resource) into aVisualBrush
(also a static-resource) and using that as theOpacityMask
for aRectangle
. Whenever the DataGrid was reloaded theRectangle
wouldn't releaseVisualBrush
references to theOpacityMask
, I used a memory-profiler tool to reveal that all theVisualBrush
objects were using the bulk of memory.I don't understand why or how this happened - but I'm glad I'm not alone (even if I had the same problem some 6.5 years later...).
My XAML was something like this:
I read that setting
IsFrozen = true
(done using this technique: https://www.codeproject.com/Tips/72221/Freeze-brushes-directly-in-the-XAML-to-improve-you ) would help memory issues with Brushes, however this seemingly had no effect at all. Weird.I thought I'd experiment and I reasoned that if the issue was leaking the
VisualBrush
then I wondered if having it as aStaticResource
was messing with object-references, so I changed it to an "owned" object, like so:This fixed the issue! And I still don't know why - I wonder if it's a bug in WPF?
On a related note, I came to realise that using a
VisualBrush
was overkill as I'm rendering just a simplePath
-VisualBrush
is expensive because it renders an entire WPF view - I also learned from other documentation thatPath
itself isn't necessary for rendering simple shapes because itself is a completeUIElement
andFrameworkElement
- which are "heavier" types.I changed my code to store the path in a
PathGeometry
value inside aGeometryDrawing
static-resource which is loaded into aDrawingBrush
:Doing this also made a dent in memory usage, and hopefully, performance.
In your project I see you're not using the path information as a resource, but the same technique applies: load your path into a
PathGeometry
(or rather,StreamGeometry
object, which is even faster and is meant for immutable geometry) and set that as theDrawing
for aDrawingBrush
.