c# - Border.Effect 绑定(bind)泄漏内存但 Border.Background 没有

标签 c# wpf

使用更新的 .NET 4.0,我发现了一个奇怪的内存泄漏,可以通过以下示例代码重现。

  • app.xml 有一些应用程序范围的资源绑定(bind)到 app.xml.cs 中的属性。造成泄漏的资源是一个<DropShadowEffect>谁的Color依赖属性绑定(bind)到 App 对象中的属性。
  • 主窗口有一个启动 LeakWindow 的按钮,其中使用了 app.xml 中定义的资源。
  • 当泄漏窗口关闭时,它不会被垃圾回收。 这个 仅当泄漏窗口使用上述 DropShadowEffect 时才会发生资源。不会发生在 SolidColorBrush 上谁的Color也绑定(bind)到相同的来源。

如果有人能告诉我为什么这个泄漏发生在 DropShadowEffect 上,我将不胜感激。但不在 SolidColorBrush 上?

App.xml

<Application x:Class="WpfSimple.App"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Application.Resources>
        <!--this one make GC unable to collect LeakWindow-->
        <DropShadowEffect x:Key="AppDropShadowColor" 
              Color="{Binding Source={x:Static Application.Current}, Path=DropShadowColor, Mode=OneWay}" />
        <!--this one does not leak-->
        <SolidColorBrush x:Key="AppBackground"
              Color="{Binding Source={x:Static Application.Current}, Path=DropShadowColor, Mode=OneWay}" />
    </Application.Resources>
</Application>

App.xml.cs 启动 MainWindow 并实现 INotifyPropertyChanged为属性(property)DropShadowColor .

 public partial class App : Application, INotifyPropertyChanged
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);        
            // start main window
            var mainWindow = new MainWindow();
            mainWindow.Show();
        }

        private Color _dropShadowColor = Colors.Blue;    
        public Color DropShadowColor
        {
            get { return _dropShadowColor; }    
            set {
                _dropShadowColor = value;
                OnPropertyChanged("DropShadowColor");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) { handler(this, new PropertyChangedEventArgs(propertyName)); }
        }
    }

MainWindow.xml 和 MainWindow.xml.cs 有一个创建 LeakWindow 的按钮,如下所示。

var win = new LeakWindow {Owner = this};
win.Show();

还有另一个按钮可以做 GC.Collect() ;

LeakWindow.xml

<Window x:Class="WpfSimple.LeakWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Leak" Height="300" Width="300">
  <Grid>
    <!--leak-->
    <Border Width="200" Height="200" BorderThickness="1" BorderBrush="Black" Effect="{StaticResource AppDropShadowColor}"/>

    <!--no leak if comment out above and uncomment below-->
    <!--<Border  Width="200" Height="200" BorderThickness="1" BorderBrush="Black" Background="{StaticResource AppBackground}"/>-->
  </Grid>
</Window>

LeakWindow.xml.cs

 public partial class LeakWindow : Window
    {
        public LeakWindow()
        {
            InitializeComponent();
        }    

        ~LeakWindow()
        {
            Debug.WriteLine("LeakWindow finalized");
        }
    }

更新

  • 我的搜索显示这可能与 DynamicResource\StaticResource cause memory leaks .但是那个在 .NET 3.5 的早期就被修补了(kb967328)。还尝试了该线程中提到的 WalkDictionary 方法,但没有帮助。
  • 将绑定(bind)模式更改为OneTime也无济于事。
  • 切换到 .NET 4.5(也已打补丁)并使用 DynamicResource没有帮助。

进一步调查显示泄漏是由 EventHandler 引起的引用自 DropShadowEffectBorder.Effect .可能是由于 DropShadowEffect 中的绑定(bind)而导致的更改通知.
不过,奇怪的是 为什么这只发生在 Border.Effect 上但不在Border.Background

工作场所
添加x:Shared=false<DropShadowEffect>在 app.xml 中可以解决这个问题。我现在可以拥有应用程序范围内定义的资源,但会降低内存效率。

最佳答案

我认为问题是由 DropShadowEffect 附加到可视化树的方式引起的。将 DropShadowEffect 移动到您的控件模板中而不是将其作为资源可能会解决泄漏问题,但是您将失去共享资源...

关于c# - Border.Effect 绑定(bind)泄漏内存但 Border.Background 没有,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31735010/

相关文章:

c# - Vim - 如何高亮模式的一部分

c# - 在 C# 中更改网站图标和中心图像库

c# - 优化套接字字节数据

c# - WPF 填充列表,为单击事件处理程序分配自定义变量以传递

wpf - 如何在 View 模型中接收 InkCanvas.StrokeCollected 事件

c# - 在 jquery 完整日历中更改事件的背景颜色

c# - 如何防止 DataGridTemplateColumn 根据某些条件进入编辑模式?

.net - 如何使元素能够在其容器外绘制?

wpf - 创建 VSIX 工具窗口时如何匹配 Visual Studio 的主题?

c# - 反射(reflect)属性 'Lists' 时出现错误