【发布时间】:2019-03-27 19:15:38
【问题描述】:
我不太确定,我的问题/错误在哪里。 我将 WPF 与 MVVM 模式结合使用,而我的问题在于登录。
我的第一次尝试效果很好。我有几个窗口,每个窗口都有自己的 ViewModel。 在登录视图模型中,我运行了以下代码:
PanelMainMessage = "Verbindung zum Server wird aufgebaut";
PanelLoading = true;
_isValid = _isSupportUser = false;
string server = Environment.GetEnvironmentVariable("CidServer");
string domain = Environment.GetEnvironmentVariable("SMARTDomain");
try
{
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, server + "." + domain))
{
// validate the credentials
PanelMainMessage = "username und passwort werden überprüft";
_isValid = pc.ValidateCredentials(Username, _view.PasswortBox.Password);
PanelMainMessage = "gruppe wird überprüft";
_isSupportUser = isSupport(Username, pc);
}
}
catch (Exception ex)
{
//errormanagement -> later
}
if (_isValid)
{
PanelLoading = false;
if (_isSupportUser)
_mainwindowviewmodel.switchToQuestionView(true);
else
_mainwindowviewmodel.switchToQuestionView(false);
}
else
PanelMainMessage = "Verbindung zum Server konnte nicht hergestellt werden";
该部分连接到 Active Directory 并首先检查登录是否成功,然后检查用户是否有某个广告组(在方法 isSupport 中)
我在视图中有一个显示,就像一个进度条。当 PanelLoading 等于 true 时,它处于活动状态。
到目前为止一切正常。
然后我创建了一个包含内容控件的主窗口,并将我的视图更改为用户控件,因此我可以交换它们。 (目的是不为每个视图打开/创建一个新窗口)。
当我现在执行代码时,我的 GUI 会阻塞,直到执行上述部分。我尝试了几种方法...
-
将代码 sn-p 移动到一个附加方法中并将其作为一个自己的线程启动:
Thread t1 = new Thread(() => loginThread()); t1.SetApartmentState(ApartmentState.STA); t1.Start();当我这样做时,我收到一个错误,即资源由另一个线程拥有,因此无法访问。 (调用线程无法访问此对象,因为不同的线程拥有它)
-
然后,尝试调用登录部分,而不是附加线程;登录包含之前的代码sn -p
Application.Current.Dispatcher.Invoke((Action)(() => { login(); }));那行不通。至少不是我的实现方式。
-
之后,我尝试在一个线程中只运行登录 sn-p 的主要部分,然后在完成后引发一个先前注册的事件,该事件将处理内容控件的更改。这就是我在线程访问另一个线程拥有的资源时遇到错误的部分,所以我想,我可以解决这个问题。
void HandleThreadDone(object sender, EventArgs e) { if (_isValid) { PanelLoading = false; _mainwindowviewmodel.switchToQuestionView(_isSupportUser); } else PanelMainMessage = "Verbindung zum Server konnte nicht hergestellt werden"; }在登录方法中我会调用 ThreadDone(this, EventArgs.Empty);完成后。好吧,关于另一个线程拥有的资源,我遇到了同样的错误。
现在我在这里寻求帮助......
我知道我的代码不是最漂亮的,我至少两次打破了 mvvm 模式背后的想法。另外我对Invoke方法了解不多,但我尽力了,在stackoverflow和其他网站上搜索了一段时间(2-3小时),没有成功。
指定线程错误发生的位置:
_mainwindowviewmodel.switchToQuestionView(_isSupportUser);
which leads to the following method
public void switchToQuestionView(bool supportUser)
{
_view.ContentHolder.Content = new SwitchPanel(supportUser);
}
这也是我不使用数据绑定的一种情况。我更改了 contentcontrol 的内容:
<ContentControl Name="ContentHolder"/>
我将如何使用数据绑定来实现这一点。属性是否应该具有 ContentControl 类型?我真的找不到答案。并且通过将其更改为DataBinding,是否可以解决线程所有权的错误?
项目结构如下: 主视图是入口点,在构造函数中数据上下文设置为当时创建的主视图模型。主视图有一个内容控件,我在其中交换我的用户控件,在本例中是我的视图。
在我的 mainviewmodel 中,我在 usercontrol 登录的开头设置了 contentcontrol 的内容,这会在其构造函数中创建一个 viewmodel 并将其设置为 datacontext。
代码 sn-ps 来自我的 loginviewmodel。希望这会有所帮助。
我以为我找到了解决方法,但它仍然不起作用。我忘了,定时器在后台是如何工作的,所以也可以这样解决。
【问题讨论】:
-
请参阅My Answer,了解关于 WPF 和 MVVM 中的 UI 线程的封送属性更改通知。它可能会对你有所帮助。
-
您使用的是哪个 .NET 框架版本?
-
@HighCore 我知道属性更改了功能并且正在使用它。我知道,我的 contentcontrol 没有数据绑定,但这仅仅是因为在 contentcontrol 上实现数据绑定对我来说似乎很困难。这是解决我问题的唯一方法吗?
-
@YuvalItzchakov .NET 4.5
-
旁注——放弃创建线程。上任务马车。
标签: c# wpf multithreading mvvm blocking