0

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

这是我的引导程序:

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);
    }
}

这是添加到该区域的我的视图的视图模型:

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();
    }
}

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

这是来自 Ants 的保留图:https ://docs.google.com/file/d/0B4XjO9pUQxBXbGFHS1luNUtyOTg/edit?usp=sharing

这是一个显示问题的测试解决方案。

另外,我也在CodePlex上发布了这个问题。

4

2 回答 2

0

看起来您的保留图中仍有对它的绑定引用。

阅读并理解以下内容:

在 Windows Presentation Foundation 中使用数据绑定时可能会发生内存泄漏

我认为这可能是你的问题,但你没有显示你的实际绑定。

于 2013-02-27T06:42:38.390 回答
0

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

在我们的 Shell.xamlIsDefault中,我们将其中一个按钮绑定到 PasswordBox 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 的依赖属性 - 所以在这方面应该很好。

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

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

<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>
于 2013-02-28T20:21:49.097 回答