PRISMアーキテクチャにWPFアプリケーションがあります。
アプリの読み込み時に「メインリージョン」に表示される「ログインビュー」があります。
ユーザーが[ログイン]を押すと、WCFサービスに接続し、ユーザーを認証して、サービスからそのユーザーの役割のリストを取得します。
次に、ユーザーの役割に応じて、「モジュールマネージャー」を使用してさまざまなモジュールをロードします。
問題は-「ログイン」ボタンが押された後のすべての作業を別のスレッドで実行したいのです。サービスへの接続などに時間がかかる可能性があり、UIがフリーズしたくないからです。
しかし、コードを「接続、認証、役割の取得、モジュールのロード」に別のスレッドで配置すると、「_ moduleManager.LoadModule」を呼び出すと、次のような例外が発生します。
多くのUIコンポーネントがこれを必要とするため、呼び出しスレッドはSTAである必要があります。
どうすればこれを解決できますか?
私はさまざまな解決策を試しました。新しいスレッドの「ApartmentState=STA」を設定しようとしましたが、役に立ちませんでした。View-Modelのコンストラクターに'Dispatcher'オブジェクトを保存し、'LoadModule'を呼び出すときに'dispatcher.Invoke'を実行することを考えましたが、それは悪い設計です(View-ModelはDispatcherを使用しないでください。テストには適していません)。
どうすればこれを解決できるのでしょうか?
'LoadModule'だけが私に悲しみを与え、他のすべてのものはうまく機能します。
。
[更新]-コードサンプルを追加:
[Export]
public class LoginViewModel : NotificationObject
{
[ImportingConstructor]
public LoginViewModel(IRegionManager regionManager, IModuleManager moduleManager)
{
this.LoginCommand = new DelegateCommand(LoginExecute, LoginCanExecute);
this._regionManager = regionManager;
this._moduleManager = moduleManager;
}
private void LoginExecute()
{
IsBusy = true; // Set this to 'true' so controls go disabled
LoginStatus = ""; // Clear the 'login status' string
Thread loginThread = new Thread(new ThreadStart(LoginWork));
loginThread.SetApartmentState(ApartmentState.STA);
loginThread.Start();
}
private void LoginWork()
{
ParamsToGetRoles param = new ParamsToGetRoles
{
Username = Username,
InputtedPassword = Password
};
try
{
// Connect to the secure service, and request the user's roles
_clientSecure = new AuthenticationServiceClient("WSHttpBinding_MyService");
_clientSecure.ClientCredentials.UserName.UserName = param.Username;
_clientSecure.ClientCredentials.UserName.Password = param.InputtedPassword;
_clientSecure.ChannelFactory.Faulted += new EventHandler(ChannelFactory_Faulted);
var local = _clientSecure.ChannelFactory.CreateChannel();
_clientSecure.GetRolesCompleted += new EventHandler<GetRolesCompletedEventArgs>(clientSecure_GetRolesCompleted);
_clientSecure.GetRolesAsync(param);
}
catch (Exception ex)
{
Console.WriteLine("Exception : " + ex.Message.ToString());
}
}
void clientSecure_GetRolesCompleted(object sender, GetRolesCompletedEventArgs e)
{
if (e.Error == null)
{
_clientSecure.Close();
LoginSuccess(e.Result.UserRoles);
}
else
{
LoginFailure("Unable to authenticate");
}
_clientSecure = null;
}
private void LoginSuccess(List<UserTypeEnum> rolesOfAuthenticatedUser)
{
LoginStatus = "Success";
if (rolesOfAuthenticatedUser.Contains(UserTypeEnum.Administrator))
{
// This is what throws the exception !
// This is called by the 'EndInvoke' of the 'GetRoles' operation,
// Which was called in the 'LoginWork' function which was run on a separate thread !
_moduleManager.LoadModule(WellKnownModuleNames.ModuleAdmin);
}
NavigateToMainMenu();
this.IsBusy = false;
}
}