2016-09-29 17 views
0

私はPrism 5.0を使用していますが、既存のビューを再利用するように設定するのに問題があります。 IRegionManager.RequestNavigate(string regionName, Uri source)が呼び出されると、以前に作成されたビューを使用する代わりに、新しいビューが作成されます。不思議なことに、CLRProfilerはまた、Prismの地域マネージャーが、以前に作成されたすべてのビューインスタンスへの参照を保持し、メモリリークを引き起こすことを示しています。Prismがナビゲーションで新しいビューを作成しないようにします

私のビューモデルはINavigationAwareを実装し、trueIsNavigationTarget()に返しますが、このメソッドは呼び出されません。私は同じ結果で同様にビューに実装しようとしました。

テストでは、ビューにIActiveAwareを実装しました。これは、別のビューに移動するとすぐに非アクティブ化されることを示しています(これは適切ではありません)。

私はこの質問を見つけました:PRISM WPF - Navigation creates new view every timeしかし、私のV-VM命名規則は答えのものと一致します(私はAutoFacを使っています)。

私は回避策を見つけました。ビューモデルのINavigationAware.OnNavigatedFrom()実装でNavigationContext.NavigationService.Region.Remove()を使用して、地域からアクティブビューを削除しました。これを行うと、Prismの地域マネージャーがビューへの参照を解放します。これはうまくいきますが、必要なときに常にビューを再作成するのは非効率的です。

ほとんどの関連する質問は、ナビゲーションイベントで新しいビューを作成する方法を尋ねるので、デフォルトの動作ではビューが再利用されると仮定します。私はここにポインタが必要です。私たちは、ビューを登録するAutoFacのAutofacExtensions.RegisterTypeForNavigation<T>(this ContainerBuilder builder, string name = null)を使用

EDIT

。ビュー間のナビゲーションにはIRegionManager.RequestNavigate()を使用します。 INavigationAwareはViewModelsに実装されています。ただし、INavigationAware.OnNavigatedTo()OnNavigatedFrom()が呼び出されますが、IsNavigationTarget()は呼び出されません(後者は、ビューがINavigationAwareを実装していても呼び出されません)。

ビューのctorにブレークポイントを設定することで、新しいビューが作成されたことを検出できます。また、CLRProfilerヒープ・ダンプは、リージョン・マネージャーに、ナビゲートされた回数だけのビューのインスタンスがあることも示しています。 ViewModelは、AutoFacで単一インスタンスとして登録されているため、一度だけ作成されます。

一時的な対策として、ビューをIRegionMemberLifetimeに実装しました。KeepAlivefalseを返します。これはあまり効果的ではありません。ビューは必要になるたびに再作成されますが、リージョン・マネージャーは以前のビューを保持できません。

+0

IRegionMemberLifetimeプロパティとKeepAliveプロパティを使用する必要があります。 –

+0

@AyyappanSubramanianビューがIRegionMemberLifetimeを実装し、KeepAliveがtrueを返す場合、リージョンマネージャはビューへの参照を保持しますが、ナビゲートするときに新しいビューを作成します(ビューにIRMLが実装されていない場合はデフォルトでなければなりません)。 KeepAliveがfalseを返す場合、ビューは破棄されるため、再作成する必要があります。私の質問は、プリズムを元のビューに再利用させる方法だったので、これは解決策ではありません。 – Drew

+0

私は現在、すべての私の見解ではないが、同じ問題を抱えています。それは私の問題を引き起こしている特定のページの下にあるようです。 – user3265613

答えて

0

IRegionManager.RequestNavigate(文字列regionName、ウリソース)が呼び出されるたびに、代わりに以前、私は、この動作を複製することはできません

を作成されたビューを使用しての新しいビューを作成します。ナビゲーションフレームワークを使用する場合、デフォルトでPrismはINavigationAwareインターフェイスを使用しているかどうかに関係なく、各ビューを再利用します。これは、リージョンマネージャーのビューを保持することを意味します(メモリーリークではなく、これは意図的に行われます)。ビューを再利用しない場合は、IRegionMemberLifetimeインターフェイスまたは属性を使用し、ビューを再利用しないようにPrismに指示する必要があります。この場合、ビューはリージョンマネージャから削除され、新しいビューが作成されます。

私のビューモデルはINavigationAwareを実装し、IsNavigationTarget()ではtrueを返しますが、メソッドは呼び出されません。私は同じ結果で同様にビューに実装しようとしました。

この場合、RequestNavigateを使用していません。 IRegion.Addを使用してリージョンを手動でリージョンに追加しているか、ViewModelがDataContextとして設定されていない可能性があります。この場合、これらのメソッドは呼び出されません。

新しいビューが作成されているかどうかはどのように判断していますか? ViewsとViewModelのctorにブレークポイントを設定していますか?ナビゲーションのためにビューを正しく登録していますか?

+0

答えをありがとう。私はいくつかを明確にするために投稿を編集しました。 – Drew

+0

古い質問を復活させるのは嫌いですが、まったく同じ問題があります。ただし、特定のビューにのみ影響します。メインアプリケーションの実行中にプリズムソースをデバッグする方法はありますか? – user3265613

+0

@ user3265613 Prismlibrary Githubページからソースを取得し、NuGetパッケージの代わりにプロジェクトファイルを参照することをお勧めします。 https://github.com/PrismLibrary/Prism/tree/master/Source/Wpf – Gusdor

0

これは古い質問です。しかし、私はちょうど自分自身でこの問題を抱えていました。もし他の人がそれを持っていれば、もう一度戻ってくる可能性があります。

問題は私が持っていたので、私のページ名でした。

ナビゲーションを簡単にするために、次のようにコンテンツを持つPageNamesクラスを作成しました。

public static class PageNames 
{ 
    public const string MyPage= "MyPageView"; 
} 

ページを登録してナビゲートするとき、私のクラスは私のページのほとんどは彼らのクラス、IE MyPageView = MyPageViewと同じ名前を持っていた以下の

Kernel.RegisterTypeForNavigation<MyPageView>(PageNames.MyPage); 

のように多少ました。しかし、いくつかのページにはページ名の「表示」部分がありませんでした。

PRISMが領域内にページが存在するかどうかをチェックすると、次のことが実行されます。

protected virtual string GetContractFromNavigationContext(NavigationContext navigationContext) 
{ 
    if (navigationContext == null) throw new ArgumentNullException(nameof(navigationContext)); 
    var candidateTargetContract = UriParsingHelper.GetAbsolutePath(navigationContext.Uri); 
    candidateTargetContract = candidateTargetContract.TrimStart('/'); 
    return candidateTargetContract; 
} 

これはページ名を返します。 MyPageView。要求ナビゲーション・コンテンツ・ローダーは、このメソッドを呼び出して、ページがリージョン内に存在するかどうかをチェックします。私は信じて

return region.Views.Where(v => 
    string.Equals(v.GetType().Name, candidateNavigationContract, 
StringComparison.Ordinal) || 
    string.Equals(v.GetType().FullName, candidateNavigationContract, StringComparison.Ordinal)); 

(直接ではなくPRISMをデバッグする方法がわから)は、ページ名は、クラス名、または名前空間を含む完全な名前と一致するかどうかをチェックしています。ページ名はクラス名と同じではないため、ページ名が見つからず、そのページの新しいインスタンスがリージョン・マネージャーに追加されます。

結論として、最良の修正は、あなたのpagename =クラス名を確認することです。

関連する問題