環境
Windowsの作成を担当するInteractionWindowPresenter
クラスがあります。それらのいくつかはモーダルである可能性があり、アプリケーションの他の部分に通知するために、開いているモーダル ウィンドウの数のカウンターを保持したいと考えています。
したがって_modalsCount
、モーダルウィンドウが開いたり閉じたりするたびに更新される変数をクラスに追加しました。
public class InteractionWindowPresenter<TWindow, TNotification>
where TWindow : System.Windows.Window
where TNotification : Prism.Interactivity.InteractionRequest.INotification
{
private static int _modalsCount = 0;
...
private bool _useModalWindow;
public InteractionWindowPresenter(InteractionRequest<TNotification> request,
bool useModalWindow = false)
{
_useModalWindow = useModalWindow;
}
public void Show()
{
var window = ...
window.Closed += (s, e) =>
{
if (_useModalWindow)
{
_modalsCount = Math.Max(0, --_modalsCount);
if (_modalsCount == 0)
ServiceLocator.Current.GetInstance<IEventAggregator>()
.GetEvent<ModalStatusChanged>().Publish(false);
}
};
if (_useModalWindow)
{
_modalsCount++;
ServiceLocator.Current.GetInstance<IEventAggregator>()
.GetEvent<ModalStatusChanged>().Publish(true);
window.ShowDialog();
}
else
window.Show();
}
}
初期化時に、各Prism モジュール- つまり。各クラスの実装IModule
- InteractionWindowPresenter
ウィンドウに表示する必要があるビューごとにインスタンス化し、それへの参照を保持します。例えば:
[ModuleExport("ClientsModule", typeof(Module),
DependsOnModuleNames = new[] { "RibbonModule", "ClientsModelModule" },
InitializationMode = InitializationMode.WhenAvailable)]
public class Module : IModule
{
InteractionWindowPresenter<ClientSelectionWindow, ClientSelection> _selectionPresenter;
public void Initialize()
{
_selectionPresenter =
new InteractionWindowPresenter<ClientSelectionWindow, ClientSelection>
(Interactions.ClientSelectionRequest, useModalWindow: true);
}
}
クラスは、InteractionWindowPresenter
すべてのモジュールおよび他のインフラストラクチャ アセンブリによって直接参照されるインフラストラクチャ アセンブリで定義されます。ランチャー アプリケーションからは参照されませんMefBootstrapper
。したがって、合成にはMEFが使用されます。
問題
初期化行にブレークポイントを設定すると、インスタンスの作成_modalsCount
時に実行されないことがわかります。InteractionWindowPresenter
代わりに、変数が各モジュールで最初に使用されたときに (そのときだけ) 実行されます。Show
メソッドが各モジュールから初めて呼び出されたとき。したがって、各モジュールには独自の値があり、その特定のモジュールのすべてのインスタンスで共有されます。
遅延評価がの好奇心beforefieldinit
によるものであることは理解しています。ただし、モジュールごとではなく、アプリケーション全体に対して 1 回だけ評価が行われることを期待していました。
また、静的コンストラクターで初期化を実行しようとしました。
static int _modalsCount;
static InteractionWindowPresenter()
{
_modalsCount = 0;
}
この場合、静的コンストラクターはインスタンス コンストラクターの実行前に呼び出されますが、インスタンスが作成されるたびに呼び出されます。したがって、変数はもはや静的ではないようです。
私の理解では、static
変数は ごとに 1 回初期化されますAppDomain
。したがって、すべてのアセンブリ (モジュールとインフラストラクチャ) が同じ にあるためAppDomain
、これは発生しないはずです。これら2つの仮定のいずれかで間違っていますか?
これまでに採用された回避策
カウンターを保持する単純なクラスを作成すると、この問題を回避できます。
static class ModalsCounter
{
private static int _modalsCount = 0;
public static int Increment()
{
return ++_modalsCount;
}
public static int Decrement()
{
_modalsCount = Math.Max(0, --_modalsCount);
return _modalsCount;
}
}
したがって、呼び出しを次のように置き換えます_modalsCount
。
ModalsCounter.Increment();
ServiceLocator.Current.GetInstance<IEventAggregator>()
.GetEvent<ModalStatusChanged>().Publish(true);
と:
if (_useModalWindow && ModalsCounter.Decrement() == 0)
ServiceLocator.Current.GetInstance<IEventAggregator>()
.GetEvent<ModalStatusChanged>().Publish(false);
それで、私はここで何が欠けていますか?静的変数のライフサイクルとスコープを何らかの形で誤解したのでしょうか、それとも Prism モジュールや MEF が私をいじっているのでしょうか?