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

Wpf 如何正确实现XAML INotifyPropertyChanged以防止GDI泄漏,wpf,binding,gdi,inotifypropertychanged,Wpf,Binding,Gdi,Inotifypropertychanged,我们有一个应用程序,它使用WPF生成一个显示工作流的图像,这是一个非常古老的应用程序,直到最近我们开始遇到GDI泄漏时,它似乎工作得很好。我不熟悉WPF或GDI泄漏,但经过一些搜索,可能与WPF绑定有关。这些文章提到了将INotifyPropertyChanged接口实现到所有绑定到XAML上的类。我也这么做了,但问题仍然存在 我试图实现INotifyPropertyChanged,以解决内存分析器提到的问题类。还尝试将用户控件的DataContext属性设置为null 下面您可以看到在两个内存

我们有一个应用程序,它使用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();
        }
    }
}


如何修复此问题以避免GDI泄漏


编辑:根据Clemens的建议调整了代码,但usercontrol仍然是主导者。

这是一个MVVM体系结构,我建议您使用MVVM Franmework,如MVVM light,它将有助于避免许多问题并做得更好。
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();
        }
    }
}

使用MVVMLight,您不需要实现INotifyPropertyChanged,框架正在做所有事情


希望这会有所帮助。

这是一个MVVM体系结构,我建议您使用MVVM Franmework,如MVVM light,它将有助于避免许多问题并编写更好的代码。 使用MVVMLight,您不需要实现INotifyPropertyChanged,框架正在做所有事情


希望这能有所帮助。

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

var source = new HwndSource(new HwndSourceParameters())
{
    RootVisual = this
};

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

var source = new HwndSource(new HwndSourceParameters())
{
    RootVisual = this
};

除此之外,您似乎不会在任何地方触发PropertyChanged事件,在从DependencyObject(如UserControl)派生的类中实现INotifyPropertyChanged也没有任何意义。DependencyObject派生类中声明的属性应该是依赖属性,它们有自己的更改通知机制。通常的基于DataContext的绑定(如
)将不再有效。与其显式设置DataContext,不如在UserControl的XAML中使用RelativeSource绑定,如
Fill=“{Binding ClockColor,RelativeSource={RelativeSource AncestorType=UserControl}}”
根据您的建议调整代码,但它仍然显示为支配者。但我不确定我是否做对了。我的评论并不是为了提供解决方案。仅仅说实现INPC(或数据绑定)与您的实际问题没有任何关系。实施它是没有意义的。好吧,我也认为实施INPC是没有用的,但是一些消息来源说这是为了防止GDI泄漏。我没有找到任何其他建议来解决我的问题。无论如何,谢谢。除了您似乎没有在任何地方触发PropertyChanged事件之外,在从DependencyObject(如UserControl)派生的类中实现INotifyPropertyChanged没有任何意义。DependencyObject派生类中声明的属性应该是依赖属性,它们有自己的更改通知机制。通常的基于DataContext的绑定(如
)将不再有效。与其显式设置DataContext,不如在UserControl的XAML中使用RelativeSource绑定,如
Fill=“{Binding ClockColor,RelativeSource={RelativeSource AncestorType=UserControl}}”
根据您的建议调整代码,但它仍然显示为支配者。但我不确定我是否做对了。我的评论并不是为了提供解决方案。仅仅说实现INPC(或数据绑定)与您的实际问题没有任何关系。实施它是没有意义的。好吧,我也认为实施INPC是没有用的,但是一些消息来源说这是为了防止GDI泄漏。我没有找到任何其他建议来解决我的问题。无论如何谢谢你