У нас есть приложение, которое использует WPF для создания изображения, показывающего рабочий процесс, оно очень старое и, кажется, работало до недавнего времени, когда мы начали испытывать утечки GDI. Я не знаком с утечками WPF или GDI, но после некоторого поиска может случиться иметь дело с привязками WPF. В упомянутых статьях реализован интерфейс INotifyPropertyChanged для всех классов, которые являются обязательными в XAML. Я так и сделал, но проблема все еще остается.
Я пытался реализовать INotifyPropertyChanged для проблемных классов, упомянутых профилировщиками памяти. Также попытался установить для свойства DataContext пользовательского элемента управления значение null.
Ниже вы видите доминаторы новых объектов, созданных между двумя снимками памяти.
Ниже вы видите 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.
РЕДАКТИРОВАТЬ: Исправлен код в соответствии с предложением Клеменса, но пользовательский контроль все еще отображается в качестве доминирующего.