我在PRISM體系結構中有一個WPF應用程序。WPF + PRISM - 不能'LoadModule'在單獨的線程
我有一個「登錄視圖」,當應用程序加載時顯示在「主要區域」中。
當用戶按'登錄' - 我連接到WCF服務,驗證用戶,並從該服務獲取該用戶的角色列表。
然後 - 根據用戶的角色 - 使用「模塊管理器」加載不同的模塊。
問題是 - 我想要在「登錄」按鈕在單獨的線程中完成後的所有工作,因爲它可能需要時間來連接到服務等,我不希望UI是凍結。
但是 - 如果我把代碼「連接,進行身份驗證,得到角色,加載模塊」在一個單獨的線程 - 我得到一個異常時,我稱之爲「_moduleManager.LoadModule」,上面寫着:
主叫線程必須是STA,因爲許多UI組件都需要這個。
我該如何解決這個問題?
我已經嘗試過不同的解決方案。 我試圖設置新線程的'Apartment State = 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;
}
}
你確定你把正確的線程的狀態設置爲STA?同時,http://stackoverflow.com/questions/2329978/the-calling-thread-must-be-sta-because-many-ui-components-require-this和其他許多人問完全相同的 – stijn 2012-07-23 10:21:44
我只是用'Dispatcher'發送LoadModules命令到主UI線程:) – Rachel 2012-07-23 13:14:19
@Rachel - 但不使用'Dispatcher'對測試目的不利?還有 - 我認爲'視圖模型'應該對UI一無所知,並且如果我使用'Dispatcher'在UI線程上做某些事情 - 這有點違背目的,不是嗎? – 2012-07-24 05:40:39