2013-02-24 46 views
0

我建立使用WPF,.NET 4中,棱鏡4.1和團結棱鏡應用。我正在使用DirectoryModuleCatalog在運行時查找模塊。我的視圖顯示在TabControl(MainRegion)中。當我從區域刪除一個視圖,該視圖和視圖模型保留在內存中,從不垃圾收集 - 在TabItem的被刪除。經過許多小時的搜索,我無法弄清楚我做錯了什麼。WPF和棱鏡4.1垃圾收集/內存問題

這裏是我的引導程序:

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

我讀過,這可能是因爲我在實例化視圖中的模塊,或者也許是視圖模型視圖?當我使用紅門內存分析器,並且經由DelegateCommand,視圖和視圖模型去除視圖都標記爲不能夠被垃圾收集。我沒有正確裁剪的參考在哪裏?

繼承人從螞蟻的保留圖:https://docs.google.com/file/d/0B4XjO9pUQxBXbGFHS1luNUtyOTg/edit?usp=sharing

這裏的顯示問題進行test solution

另外,我貼在CodePlex的問題也是如此。

+0

野生刺在黑暗中:HTTP://計算器。COM /問題/ 516617 /什麼 - 是最微弱的事件圖案使用功能於WPF應用 – 2013-02-24 06:26:41

+1

嘿,克里斯。我看着你的項目。它看起來像你的ViewModel實現IDisposable。我發現如果Dispose()沒有被調用(WPF,與WinForms不同,不會使用IDisposable),這可能會對生命週期產生一些奇怪的影響。 IDisposable適用於像關閉數據庫連接等非託管資源,但有更好的方法。試着拿出來看看會發生什麼。 – 2013-02-28 18:15:58

+0

我應該提到的另一件事是,你應該確保你是一個很好的衡量你的對象的一生。集合不是非常確定的,我在WPF應用程序中發現它有時可能需要一段時間才能收集對象。你的螞蟻圖形看起來不錯 - 有你的視圖模型引用的東西都看向在那裏有一個WeakReference的休息的地方,所以他們不應該被釘扎的對象。 – 2013-02-28 18:18:37

回答

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,而是將一個keydown事件添加到PasswordBox,如果它是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> 
0

它看起來像你還有一個綁定引用它仍然在你的保留圖。

閱讀並瞭解以下內容:

A memory leak may occur when you use data binding in Windows Presentation Foundation

我認爲這可能是你的問題,但你並沒有表現出你的實際綁定。

+0

嗨艾倫,是的,它確實看起來是從一個綁定的地方。我創建了一個測試溶液這裏在我的模塊僅結合(通過INotifyPropertyChanged的)至1個文本框,但在模塊中視圖和視圖模型保持在存儲器中。 https://docs.google.com/file/d/0B4XjO9pUQxBXVEtJaW8yYWV1SGs/edit?usp=sharing。問題在於發現綁定越來越糟糕 – 2013-02-27 15:16:59

+0

在我的示例應用程序中有兩個綁定。一個字符串屬性到一個文本框文本和一個委託命令到一個按鈕的命令。持有這些屬性的對象實現INotifyPropertyChanged。即使當我將TextBox綁定到OneTime時,對象仍保留在內存中。在我們的實際應用程序中有大量的綁定(MVVM和通過DataTemplates的viewmodelfirst),因此清除所有這些綁定不是一種選擇。 – 2013-02-27 16:00:31