[我们有一个使用WPF生成显示工作流程的图像的应用程序,它很旧,并且似乎可以正常工作,直到最近我们开始遇到GDI泄漏。我不熟悉WPF或GDI泄漏,但是经过一番搜索之后,可能与WPF绑定有关。文章提到了实现INotifyPropertyChanged接口到XAML上绑定的所有类。所以我做到了,但问题仍然存在。
我试图将INotifyPropertyChanged实现为内存分析器提到的有问题的类。还尝试将用户控件的DataContext属性设置为null。
下面您将看到在两个内存快照之间创建的新对象的控制者。
<< img src =“ https://image.soinside.com/eyJ1cmwiOiAiaHR0cHM6Ly9pLmltZ3VyLmNvbS9UZ2N5Y04yLnBuZyJ9” alt =“忙碌的猫”>
在下面您会看到统治者的xaml和代码。
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace Priox.Core.Graph.UserControls
{
public partial class IndicatorClock : UserControl
{
public enum ClockTypes
{
None,
FixSla,
ResponseSla,
FixOla,
ResponseOla
};
public static readonly DependencyProperty ClockTypeProperty =
DependencyProperty.Register("ClockType", typeof(ClockTypes),
typeof(IndicatorClock), new FrameworkPropertyMetadata(ClockTypes.None));
public ClockTypes ClockType
{
get { return (ClockTypes)GetValue(ClockTypeProperty); }
set { SetValue(ClockTypeProperty, value); }
}
internal bool IsClockVisible { get; set; }
public Visibility ClockVisibility
{
get
{
if (IsClockVisible)
return System.Windows.Visibility.Visible;
return System.Windows.Visibility.Collapsed;
}
}
public double ClockBorderThickness
{
get
{
return 1.5;
}
}
public double ClockTimeThickness
{
get
{
return 2.0;
}
}
public Brush ClockColor
{
get
{
switch (ClockType)
{
case ClockTypes.FixSla:
return new SolidColorBrush(Colors.Cyan);
case ClockTypes.ResponseSla:
return new SolidColorBrush(Colors.DarkMagenta);
case ClockTypes.FixOla:
return new SolidColorBrush(Colors.Yellow);
case ClockTypes.ResponseOla:
return new SolidColorBrush(Colors.DarkSlateGray);
}
return new SolidColorBrush(Colors.Black);
}
}
public IndicatorClock()
{
InitializeComponent();
}
}
}
<UserControl x:Class="Priox.Core.Graph.UserControls.IndicatorClock"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid Margin="2" Visibility="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=ClockVisibility, FallbackValue=Visible}">
<Grid.Effect>
<DropShadowEffect BlurRadius="3" ShadowDepth="3" Opacity="0.7"/>
</Grid.Effect>
<Ellipse StrokeThickness="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=ClockBorderThickness, FallbackValue=4.0}" Stroke="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=ClockColor, FallbackValue=Red}" />
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="7*"/>
<RowDefinition Height="2*"/>
<RowDefinition Height="7*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="7*" />
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="7*" />
</Grid.ColumnDefinitions>
<Ellipse Fill="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=ClockColor, FallbackValue=Red}" Grid.Row="1" Grid.Column="1"/>
</Grid>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition Height="8*"/>
<RowDefinition Height="10*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="6*"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="6*"/>
</Grid.ColumnDefinitions>
<Line Grid.Row="1" Grid.Column="1" Y1="0" Y2="1" Stroke="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=ClockColor, FallbackValue=Red}" Stretch="Fill" StrokeThickness="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=ClockTimeThickness, FallbackValue=8.0}"/>
</Grid>
<Grid>
<Grid.LayoutTransform>
<RotateTransform CenterX="0.5" CenterY="0.5" Angle="90"/>
</Grid.LayoutTransform>
<Grid.RowDefinitions>
<RowDefinition Height="4*"/>
<RowDefinition Height="6*"/>
<RowDefinition Height="10*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="6*"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="6*"/>
</Grid.ColumnDefinitions>
<Line Grid.Row="1" Grid.Column="1" Y1="0" Y2="1" Stroke="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=ClockColor, FallbackValue=Red}" Stretch="Fill" StrokeThickness="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=ClockTimeThickness, FallbackValue=8.0}"/>
</Grid>
</Grid>
</UserControl>
如何解决此问题,使其不再发生GDI泄漏。
编辑:根据Clemens的建议调整了代码,但用户控件仍然显示为控制者。
它似乎是MVVM架构,我建议您使用MVVM light这样的MVVM Franmework,它将有助于避免很多问题并编写更好的代码。http://www.mvvmlight.net/使用MVVMLight,您不需要实现INotifyPropertyChanged,框架就可以完成所有工作。
希望这会有所帮助。
好,我解决了我的问题,它与XAML的外观无关,我之所以查看XAML,是因为我使用的所有内存分析器都告诉我这就是问题所在。实际的问题是UserControl被设置为应用程序根本不使用的对象。因此,XAML不会被垃圾收集,而是通过这种方式增加了GDI计数。
var source = new HwndSource(new HwndSourceParameters())
{
RootVisual = this
};