我使用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();
}
}
我读过它可能是因为我在模块中实例化视图或者视图中的viewmodel?当我使用Red Gate Memory Profiler并通过DelegateCommand删除视图时,视图和视图模型都被标记为无法进行垃圾回收。我没有正确切割的参考在哪里?
来自Ants的保留图:https://docs.google.com/file/d/0B4XjO9pUQxBXbGFHS1luNUtyOTg/edit?usp=sharing
这是显示问题的test solution。
另外,我也在CodePlex上发布了这个问题。
答案 0 :(得分:0)
看起来您的保留图中仍然存在对它的绑定引用。
阅读并理解以下内容:
A memory leak may occur when you use data binding in Windows Presentation Foundation
我认为这可能是你的问题,但你没有展示你的实际绑定。
答案 1 :(得分:0)
终于找到了问题的根本原因....
在我们的Shell.xaml中,我们将其中一个按钮中的IsDefault
绑定到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>