【问题标题】:WPF - Border with a OpacityMask/VisualBrush: Memory LeaksWPF - 带有 OpacityMask/VisualBrush 的边框:内存泄漏
【发布时间】:2011-06-07 17:52:20
【问题描述】:

关于我的应用的简要说明:

我正在开发的应用程序就是这样一个贺卡设计器。想象一下有一个背景图像,以及无限数量的“层”(特别是图片)留在背景上并且可以移动、调整大小、前后移动等等......

也可以在这些图层上应用特定的形状,如星形、椭圆形,.. 制作卡片后,可以将其保存为 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 Path(这是我正在应用的形状)。

所以,原则是如果我有名为*im_the_problem*的边框,则不会释放内存。如果我评论 *im_the_problem* (所以我只会有没有形状的矩形图层/图片)一切都像魅力一样工作,没有内存泄漏。

问题应该出在 OpacityMask + VisualBrush。

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

谢谢。

【问题讨论】:

    标签: memory-leaks binding visualbrush opacitymask


    【解决方案1】:

    您也许可以尝试将 MyMask.Data 绑定到实际的 Path.Data,并将 Path.Fill 设置为从图像创建的 ImageBrush?

    【讨论】:

      【解决方案2】:

      你需要冻结你的 VisualBrush ;)

      【讨论】:

        【解决方案3】:

        我在DataGrid 的列模板中遇到了这个问题,我将&lt;Canvas&gt;&lt;Path /&gt;&lt;/Canvas&gt;(作为静态资源)转换为VisualBrush(也是静态资源)并将其用作@987654325 @ 为Rectangle。每当重新加载 DataGrid 时,Rectangle 不会释放 VisualBrushOpacityMask 的引用,我使用内存分析器工具显示所有 VisualBrush 对象都在使用大量内存。

        我不明白为什么或如何发生这种情况 - 但我很高兴我并不孤单(即使大约 6.5 年后我遇到了同样的问题......)。

        我的 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 本身对于渲染简单形状不是必需的,因为它是完整的 UIElementFrameworkElement - 它们是“更重”的类型。

        我更改了代码以将路径存储在 GeometryDrawing 静态资源中的 PathGeometry 值中,该静态资源已加载到 DrawingBrush 中:

        <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

        【讨论】:

          猜你喜欢
          • 2010-12-28
          • 1970-01-01
          • 2017-03-01
          • 1970-01-01
          • 2011-02-21
          • 1970-01-01
          • 1970-01-01
          • 2010-12-05
          相关资源
          最近更新 更多