如何正确实施XAML INotifyPropertyChanged以防止GDI泄漏

问题描述 投票:1回答:2

[我们有一个使用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的建议调整了代码,但用户控件仍然显示为控制者。

wpf binding gdi inotifypropertychanged
2个回答
0
投票

它似乎是MVVM架构,我建议您使用MVVM light这样的MVVM Franmework,它将有助于避免很多问题并编写更好的代码。http://www.mvvmlight.net/使用MVVMLight,您不需要实现INotifyPropertyChanged,框架就可以完成所有工作。

希望这会有所帮助。


0
投票

好,我解决了我的问题,它与XAML的外观无关,我之所以查看XAML,是因为我使用的所有内存分析器都告诉我这就是问题所在。实际的问题是UserControl被设置为应用程序根本不使用的对象。因此,XAML不会被垃圾收集,而是通过这种方式增加了GDI计数。

var source = new HwndSource(new HwndSourceParameters())
{
    RootVisual = this
};
© www.soinside.com 2019 - 2024. All rights reserved.