2011-06-07 64 views
1

有关我的应用程序的简要说明:WPF - 边境与OpacityMask/VisualBrush:内存泄漏

在我工作的应用程序是这样的贺卡设计师。想象一下,有背景图像和无限数量的“层”(特别是图片),可以保持背景,并可以移动,调整大小,前后移动等等。

它也可以应用这些图层的特定形状,如星形,椭圆形等等。卡片制作完成后,可以保存为jpeg文件。

问题

一切正常,但我检测到时的形状施加到层中,产生内存泄漏。

下面是每个层的用户控件的代码:

<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中。

我做错了什么? 还是有一个已知的问题?有没有办法以不同的方式做同样的事情(对图片应用形状..)?

谢谢。

回答

0

你也许可以尝试MyMask.Data结合实际Path.Data和Path.Fill设置从图像创建的图像刷?

0

我曾在一个DataGrid的柱模板)这个问题我在那里用<Canvas><Path /></Canvas>(作为静态资源为VisualBrush(也是一种静态的资源)并将其作为OpacityMask用于Rectangle。每当DataGrid中被重新加载Rectangle不会释放VisualBrush引用到OpacityMask,我用一个内存分析器工具来显示所有的VisualBrush对象是使用大量的内存。

我不明白为什么或如何发生的 - 但我很高兴我不是一个人(即使我约650年后有同样的问题...)。

我的XAML是这样的:

<DataGrid.Resources> 

    <Canvas x:Key="icon" ...> 
     <Path ... /> 
    </Canvas> 

    <VisualBrush x:Key="iconBrush" Stretch="Uniform" Visual="{StaticResource icon}" /> 

</DataGrid.Resources> 

<DataGrid.Columns> 

    <DataGridTemplateColumn> 
     <DataGridTemplateColumn.CellTemplate> 
      <DataTemplate> 
       <Rectangle 
        Fill="{Binding Foreground, ElementName=myDataGrid}" 
        Width="14" 
        Height="14" 
        Margin="4" 
        Visibility="{Binding IconVisibility}" 
        OpacityMask="{StaticResource iconBrush}" 
       /> 
      </DataTemplate> 
     </DataGridTemplateColumn.CellTemplate> 
    </DataGridTemplateColumn> 

    ... 

</DataGrid.Columns> 

,我读了设置IsFrozen = true(使用这种技术进行:https://www.codeproject.com/Tips/72221/Freeze-brushes-directly-in-the-XAML-to-improve-you)将帮助记忆的问题用刷子,然而,这看似没有任何效果可言。奇怪的。

我以为我会做实验,我推断如果问题泄露VisualBrush然后我想知道是否它作为StaticResource搞乱了对象引用,所以我将它更改为“拥有”对象,就像这样:

<DataGridTemplateColumn> 
     <DataGridTemplateColumn.CellTemplate> 
      <DataTemplate> 
       <Rectangle 
        Fill="{Binding Foreground, ElementName=myDataGrid}" 
        Width="14" 
        Height="14" 
        Margin="4" 
        Visibility="{Binding IconVisibility}" 
       > 
        <VisualBrush Stretch="Uniform" Visual="{StaticResource iconBrush}" /> 
       </Rectangle> 
      </DataTemplate> 
     </DataGridTemplateColumn.CellTemplate> 
    </DataGridTemplateColumn> 

修复了这个问题!我仍然不知道为什么 - 我想知道这是WPF中的错误吗?

在一个相关的说明,我才明白,使用VisualBrush是矫枉过正,因为我的渲染只是一个简单的Path - VisualBrush是昂贵的,因为它呈现一个完整的WPF观点 - 我也从其他文件得知Path本身ISN对于渲染简单形状是必要的,因为它本身是一个完整的UIElementFrameworkElement--它们是“较重”的类型。

我改变了我的代码存储在PathGeometry值的路径被加载到DrawingBrush一个GeometryDrawing静态资源内:

<GeometryDrawing x:Key="iconDrawing" Brush="Black" Geometry="..." /> 

<Rectangle 
    Fill="{Binding Foreground, ElementName=myDataGrid}" 
    Width="14" 
    Height="14" 
    Margin="4" 
    Visibility="{Binding IconVisibility}" 
    OpacityMask="{StaticResource iconBrush}" 
> 
    <DrawingBrush Stretch="Uniform" Drawing="{StaticResource iconDrawing}" /> 
</Rectangle> 

这样做也取得了内存使用量的凹痕,并希望,性能。

在你的项目中,我看你不使用的路径信息作为一种资源,但同样的技术应用于:加载路径为PathGeometry(或者更确切地说,StreamGeometry对象,它是更快,是为不可变的几何)并将其设置为DrawingDrawingBrush