WPF和Prism 4.1垃圾回收/内存问题 [英] WPF & Prism 4.1 Garbage Collection / Memory Issues

查看:126
本文介绍了WPF和Prism 4.1垃圾回收/内存问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用WPF,.Net 4,Prism 4.1和Unity构建了Prism应用程序.我正在使用DirectoryModuleCatalog在运行时查找模块.我的视图显示在TabControl(MainRegion)中.当我从区域中删除视图时,该视图和视图模型仍保留在内存中,并且永远不会收集垃圾-该Tabitem已删除.经过数小时的搜索,我无法弄清楚自己在做什么.

I built a Prism application using WPF, .Net 4, Prism 4.1, and Unity. I'm using a DirectoryModuleCatalog to find modules at runtime. My views are displayed in a TabControl (MainRegion). When I remove a view from the region, the view and viewmodel remain in memory and never get garbage collected - the tabitem is removed. After many hours searching, I cannot figure out what I'm doing wrong.

这是我的引导程序:

public class Bootstrapper : UnityBootstrapper
{
    protected override void InitializeShell()
    {
        base.InitializeShell();
        App.Current.MainWindow = (Window)Shell;
        App.Current.MainWindow.Show();
    }

    protected override DependencyObject CreateShell()
    {
        var shell = new Shell();
        return shell;
    }

    protected override IModuleCatalog CreateModuleCatalog()
    {
        return new DirectoryModuleCatalog() { ModulePath = @".\Modules" };
    }
}

这是我的模块:

[Module(ModuleName = "ModuleA")]
public class Module : IModule
{
    private IRegionManager _regionManager;

    public Module(IRegionManager regionManager)
    {
        _regionManager = regionManager;
    }

    public void Initialize()
    {
        var view = new UserControl1();
        //_regionManager.RegisterViewWithRegion("MainRegion", typeof(UserControl1));
        _regionManager.Regions["MainRegion"].Add(view, "ModuleA");
        _regionManager.Regions["MainRegion"].Activate(view);
    }
}

以下是我的视图的视图模型,该视图模型已添加到该区域:

And heres the viewmodel for my view that gets added to the region:

public class ViewModel
{
    public DelegateCommand RemoveView { get; set; }

    public ViewModel()
    {
        RemoveView = new DelegateCommand(() =>
            {
                var regionManager = ServiceLocator.Current.GetInstance<IRegionManager>();
                var view = regionManager.Regions["MainRegion"].GetView("ModuleA");
                regionManager.Regions["MainRegion"].Deactivate(view);
                regionManager.Regions["MainRegion"].Remove(view);
            });
    }
}

下面是该视图的代码:

public partial class UserControl1 : UserControl
{
    public UserControl1()
    {
        InitializeComponent();

        this.DataContext = new ViewModel();
    }
}

我已经读到这可能是因为我正在实例化模块中的视图或实例化视图中的viewmodel?当我使用Red Gate Memory Profiler并通过DelegateCommand删除视图时,该视图和viewmodel都被标记为无法进行垃圾收集.我没有适当剪切的参考在哪里?

I've read that it could be because I'm instantiating the view in the module or perhaps the viewmodel in the view? When I use Red Gate Memory Profiler, and remove the view via the DelegateCommand, the view and viewmodel are both flagged as not being able to be garbage collected. Where is the reference that I'm not properly cutting?

此处显示了来自Ants的保留图: https://docs.google .com/file/d/0B4XjO9pUQxBXbGFHS1luNUtyOTg/edit?usp = sharing

Heres the retention graph from Ants: https://docs.google.com/file/d/0B4XjO9pUQxBXbGFHS1luNUtyOTg/edit?usp=sharing

这是测试解决方案,用于显示问题.

我也将问题发布在 CodePlex 上.

推荐答案

最终找到了我的问题的根本原因....

Finally found the root cause of my problem....

在Shell.xaml中,我们将其中一个按钮中的IsDefault绑定到PasswordBox的IsKeyboardFocused:

In our Shell.xaml we were binding IsDefault in one of our buttons to a PasswordBox's IsKeyboardFocused:

<Button Style="{DynamicResource RedSubmitButtonStyle}" IsDefault="{Binding ElementName=passwordBox1, Path=IsKeyboardFocused}" Command="{Binding LoginCommand}" Content="Login" Height="23" HorizontalAlignment="Left" Margin="145,86,0,0" Name="button1" VerticalAlignment="Top" Width="75" />

IsKeyboardFocused是MSDN的依赖项属性-因此在这方面应该很好.

IsKeyboardFocused, is a dependency property according to MSDN - so should be good on that end.

它与我们在密码"框中具有的附加属性有关,该属性使我们可以绑定到输入的密码.即使我们隐藏了ChildWindow(来自WPF工具箱的扩展),焦点仍然集中在该密码框上.因此,我没有使用IsDefault,而是将了一个keydown事件添加到了PasswordBox中,如果它是Key.Enter,我将更改焦点化的UI控件并将该人登录到程序中.

It was related to the attached property we had on the Password box that allows us to bind to the Password entered. The focus was remaining on that password box even after we hid the ChildWindow (from WPF toolkit extended). So instead of using IsDefault, I added a keydown event to the PasswordBox and if it was Key.Enter, I would change the focused UI control and log the person into the program.

这是我们Shell.xaml文件的全部内容

Here's the full contents of our Shell.xaml file

<Grid x:Name="MainGrid" core:SharedResourceDictionary.MergedDictionaries="TabControlThemes;MenuThemes;ButtonThemes;DataGridThemes;TreeViewThemes;ComboBoxThemes;ListBoxThemes;GroupBoxThemes;ToggleSwitchThemes">

    <DockPanel>
        <ContentControl x:Name="menuContent" DockPanel.Dock="Top" prism:RegionManager.RegionName="MenuRegion" />
        <ContentControl DockPanel.Dock="Bottom" prism:RegionManager.RegionName="FooterRegion" />
        <ContentControl DockPanel.Dock="Top" prism:RegionManager.RegionName="MainContentRegion" />
    </DockPanel>

    <StackPanel Orientation="Horizontal" Panel.ZIndex="4" HorizontalAlignment="Right" VerticalAlignment="Top">
        <Button Visibility="{Binding IsFullScreenToggleVisible, Converter={StaticResource visConv}}" Command="{Binding ToggleFullScreen}" Height="50" Name="button4" Width="70" HorizontalAlignment="Right" Margin="0,10,10,0" VerticalAlignment="Top">
            <Button.Content>
                <TextBlock FontSize="12" FontWeight="Bold" TextWrapping="Wrap" TextAlignment="Center" HorizontalAlignment="Center" VerticalAlignment="Center" Text=" Toggle Full Screen" />
            </Button.Content>
        </Button>

        <Button Visibility="{Binding IsAppCloseButtonVisible, Converter={StaticResource visConv}}" Command="{Binding ShutdownApplication}" Height="50" Name="button3" Width="50" HorizontalAlignment="Right" Margin="0,10,10,0" VerticalAlignment="Top">
            <Button.Content>
                <Image Source="..\Graphics\close.png" Name="image1" />
            </Button.Content>
        </Button>
    </StackPanel>

    <xctk:ChildWindow Name="loginChildWindow" Panel.ZIndex="3" CloseButtonVisibility="Collapsed" FocusedElement="{Binding ElementName=usernameTextBox}" WindowStartupLocation="Center" WindowState="{Binding IsVisible, Mode=TwoWay, Converter={StaticResource boolConverter}}" IsModal="True" OverlayOpacity="1" Caption="Pioneer Login" Height="164" Width="261">
        <xctk:ChildWindow.OverlayBrush>
            <ImageBrush Stretch="None" Viewport="0,0,46,29" ViewportUnits="Absolute" ImageSource="../Graphics/escheresque.png" TileMode="Tile" />
        </xctk:ChildWindow.OverlayBrush>
        <xctk:BusyIndicator IsBusy="{Binding IsLoginBusy}" BusyContent="Authenticating...">
            <Grid>
                <TextBox GotFocus="usernameTextBox_GotFocus" Text="{Binding Username, UpdateSourceTrigger=PropertyChanged}" Height="23" HorizontalAlignment="Left" Margin="99,20,0,0" Name="usernameTextBox" VerticalAlignment="Top" Width="120">
                    <TextBox.InputBindings>
                        <KeyBinding Key="Enter" Command="{Binding LoginCommand}" />
                    </TextBox.InputBindings>
                </TextBox>
                <Label Content="Username" Height="28" HorizontalAlignment="Left" Margin="28,18,0,0" Name="label1" VerticalAlignment="Top" />
                <Label Content="Password" Height="28" HorizontalAlignment="Left" Margin="29,47,0,0" Name="label2" VerticalAlignment="Top" />
                <PasswordBox attach:PasswordBoxAssistant.BindPassword="True" attach:PasswordBoxAssistant.BoundPassword="{Binding Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Height="23" HorizontalAlignment="Left" Margin="100,50,0,0" Name="passwordBox1" VerticalAlignment="Top" Width="120" />
                <Button Style="{DynamicResource RedSubmitButtonStyle}" IsDefault="{Binding ElementName=passwordBox1, Path=IsKeyboardFocused}" Command="{Binding LoginCommand}" Content="Login" Height="23" HorizontalAlignment="Left" Margin="145,86,0,0" Name="button1" VerticalAlignment="Top" Width="75" />
                <Button Style="{DynamicResource RedSubmitButtonStyle}" Command="{Binding LazyLoginCommand}" Visibility="{Binding IsDebugMode, Converter={StaticResource visConv}}" Content="Quick Login" Height="23" HorizontalAlignment="Left" Margin="23,87,0,0" Name="button2" VerticalAlignment="Top" Width="89" />
            </Grid>
        </xctk:BusyIndicator>
    </xctk:ChildWindow>

</Grid>

这篇关于WPF和Prism 4.1垃圾回收/内存问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆