2011-06-07 56 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