gpt4 book ai didi

C# WPF MVVM 阻塞 UI 线程

转载 作者:太空宇宙 更新时间:2023-11-03 15:53:42 26 4
gpt4 key购买 nike

我不太确定,我的问题/错误在哪里。我将 WPF 与 MVVM 模式结合使用,我的问题出在登录上。

我的第一次尝试效果很好。我有几个窗口,每个窗口都有自己的 ViewModel。在登录 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 中)

我在 View 中有一个显示,就像一个进度条。 PanelLoading 为真时有效。

到目前为止一切正常。

然后我创建了一个带有内容控件的主窗口,并将我的 View 更改为用户控件,这样我就可以交换它们。 (目的是不为每个 View 打开/创建一个新窗口)。

当我现在执行代码时,我的 GUI 会阻塞,直到上述部分被执行。我尝试了几种方法...

  • 将代码片段移动到另一个方法中并将其作为自己的线程启动:

    Thread t1 = new Thread(() => loginThread());
    t1.SetApartmentState(ApartmentState.STA);
    t1.Start();

    当我这样做时,我收到一个错误消息,指出资源由另一个线程拥有,因此无法访问。 (调用线程无法访问此对象,因为另一个线程拥有它)

  • 然后,尝试调用登录部分,而不是额外的线程;包含前面代码片段的登录

    Application.Current.Dispatcher.Invoke((Action)(() =>
    {
    login();
    }));

    那是行不通的。至少不是我的实现方式。

  • 之后,我尝试在一个线程中只运行登录片段的主要部分,并在完成后引发一个先前注册的事件,该事件将处理内容控件的更改。这就是我在线程访问另一个线程拥有的资源时遇到错误的部分,所以我想,我可以解决这个问题。

    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);
}

这也是我没有使用数据绑定(bind)的一种情况。我更改了内容控件的内容:

 <ContentControl Name="ContentHolder"/>

我将如何使用数据绑定(bind)实现这一点。该属性是否应具有 ContentControl 类型?我真的找不到答案。通过将其更改为 DataBinding,是否可以解决线程所有权的错误?

项目结构如下:主视图是入口点,在构造函数中,数据上下文设置为当时创建的主视图模型。主视图有一个内容控件,我可以在其中切换我的用户控件,在本例中是我的 View 。

在我的 mainviewmodel 中,我在 usercontrol 登录的开头设置了 contentcontrol 的内容,它在其构造函数中创建了一个 viewmodel 并将其设置为 datacontext。

代码片段来 self 的登录 View 模型。希望这会有所帮助。

我以为我找到了解决方法,但它仍然不起作用。我忘记了,计时器在后台是如何工作的,所以也可以这样解决。

最佳答案

问题是 WPF 或一般的 XAML 框架不允许从其他线程修改主线程上的可视元素。为了解决这个问题,您应该区分哪部分代码是从第二个线程更新 View 的。在你的情况下,我可以看到:

_view.ContentHolder.Content = new SwitchPanel(supportUser);

改变 View 。为了解决这个问题,你可以试试这个 answer .其中我使用同步上下文来进行线程间的通信。

解决它的另一种方法(这可能是调度程序的错误用法)是使用调度程序将修改 View 的操作“发送”到主线程。像这样的事情:

var dispatcher = Application.Current.Dispatcher;

//also could be a background worker
Thread t1 = new Thread(() =>
{
dispatcher .Invoke((Action)(() =>
{
login(); //or any action that update the view
}));
//loginThread();
});
t1.SetApartmentState(ApartmentState.STA);
t1.Start();

希望这有助于...

关于C# WPF MVVM 阻塞 UI 线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24686346/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com