C# 棱镜&x27;s delegates命令内存泄漏

C# 棱镜&x27;s delegates命令内存泄漏,c#,wpf,memory-leaks,prism,C#,Wpf,Memory Leaks,Prism,有了这段代码,你可以100%地重现我的问题。我创建了一个“父”视图模型: using Prism.Commands; using Prism.Mvvm; using System.Collections.ObjectModel; namespace WpfApplication1 { public class ViewModel : BindableBase { public ObservableCollection<ChildViewModel> Ite

有了这段代码,你可以100%地重现我的问题。我创建了一个“父”视图模型:

using Prism.Commands;
using Prism.Mvvm;
using System.Collections.ObjectModel;

namespace WpfApplication1 {
    public class ViewModel : BindableBase {

        public ObservableCollection<ChildViewModel> Items { get; set; }

        public DelegateCommand<ChildViewModel> CloseItem { get; set; }

        public ViewModel() {
            CloseItem = new DelegateCommand<ChildViewModel>(OnItemClose);

            Items = new ObservableCollection<ChildViewModel>(new[] {
                new ChildViewModel { Name = "asdf" },
                new ChildViewModel { Name = "zxcv" },
                new ChildViewModel { Name = "qwer" },
                new ChildViewModel { Name = "fdgz" },
                new ChildViewModel { Name = "hgjkghk" }
            });
        }

        private void OnItemClose(ChildViewModel obj) {
            Items.Remove(obj);
        }
    }
}
如您所见,我在每个
ChildViewModel
中声明了一个10mb数组。现在来看:

public partial class MainWindow : Window {
    public MainWindow() {
        InitializeComponent();

        DataContext = new ViewModel();
    }
}

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApplication1"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <TabControl ItemsSource="{Binding Items}">
        <TabControl.ItemTemplate>
            <DataTemplate>
                <DockPanel>
                    <TextBlock Text="{Binding Path=Name}" DockPanel.Dock="Left" Margin="2,3,0,2" />
                    <Button DockPanel.Dock="Right" BorderThickness="0" Background="Transparent" 
                            Margin="10,2,2,2" 
                            Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TabControl}}, Path=DataContext.CloseItem}" 
                            CommandParameter="{Binding}">
                        <Button.Content>
                            <TextBlock FontWeight="Bold" Text="X" />
                        </Button.Content>
                    </Button>
                </DockPanel>
            </DataTemplate>
        </TabControl.ItemTemplate>
    </TabControl>
</Window>
没有内存泄漏-这意味着调试工具没有显示任何已处理的
ChildViewModel
实例。我不知道这是Prism特有的问题,还是wpf的某种怪癖


我正在使用.net和prism库的最新版本。

您是否检查过自定义ICommand实现是否具有相同的行为

由于一个相关的bug,当我们删除weakreference时,可能引入了这个内存泄漏

请您在此处报告这一问题:

我们将进行调查和调查


编辑:我很高兴听到这不是Prism问题:)

似乎我找到了解决这个问题的方法(至少在我的应用程序中)-我停止了直接绑定到
ChildViewModel
实例,而是将
CommandParameter
绑定到
ChildViewModel
Name
属性。然后,在
ViewModel
中,我只是查看Items集合并删除具有匹配属性值的项。现在VS诊断工具没有显示任何本应进行GCed但未进行GCed的对象,因此内存泄漏消失


Prism团队正在分析这个问题:

出于好奇,如果删除CommandParameter=“{Binding}”部分会怎么样?它仍然显示内存泄漏吗?不。正如我上面所写的,如果我用ClickEvent替换命令,它工作正常。我的意思是,如果保留命令,但只是删除CommandParameter=“{Binding}”部分,它仍然显示内存泄漏吗?没有CommandParameter,它不会显示内存泄漏。CommandParameter=“{Binding}”创建从按钮到绑定viewmodel的引用,该引用看起来像是从集合中移除项后保留到的引用。您真的需要CommandParameter=“{Binding}”部分,还是可以切换以从TabControl.SelectedItem获取当前的viewmodel?我没有使用自定义的
ICommand
实现检查它。我明天报告。谢谢你的回答!
public partial class MainWindow : Window {
    public MainWindow() {
        InitializeComponent();

        DataContext = new ViewModel();
    }
}

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApplication1"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <TabControl ItemsSource="{Binding Items}">
        <TabControl.ItemTemplate>
            <DataTemplate>
                <DockPanel>
                    <TextBlock Text="{Binding Path=Name}" DockPanel.Dock="Left" Margin="2,3,0,2" />
                    <Button DockPanel.Dock="Right" BorderThickness="0" Background="Transparent" 
                            Margin="10,2,2,2" 
                            Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TabControl}}, Path=DataContext.CloseItem}" 
                            CommandParameter="{Binding}">
                        <Button.Content>
                            <TextBlock FontWeight="Bold" Text="X" />
                        </Button.Content>
                    </Button>
                </DockPanel>
            </DataTemplate>
        </TabControl.ItemTemplate>
    </TabControl>
</Window>
Click="Button_Click"

private void Button_Click(object sender, RoutedEventArgs e) {
            (DataContext as ViewModel).CloseItem.Execute(((sender as Button).DataContext as ChildViewModel));
        }