Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/307.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 是否由于未使用Dispatcher而导致错误/问题?_C#_Wpf_Multithreading - Fatal编程技术网

C# 是否由于未使用Dispatcher而导致错误/问题?

C# 是否由于未使用Dispatcher而导致错误/问题?,c#,wpf,multithreading,C#,Wpf,Multithreading,我用这个很棒的工具在WPF中进行模态对话 使用这个框架,当用户单击第一个对话框中的按钮时,我试图获得一个模式对话框来覆盖另一个模式对话框。这个框架的DemoApp中有一个例子,它只使用\u dialogmanager首先弹出一个消息对话框,然后弹出另一个 从DemoApp执行此操作的代码如下所示: private void ShowLayeredDialog() { _dialogManager .CreateMessageDialog("Wait 2 secs...",

我用这个很棒的工具在WPF中进行模态对话

使用这个框架,当用户单击第一个对话框中的按钮时,我试图获得一个模式对话框来覆盖另一个模式对话框。这个框架的
DemoApp
中有一个例子,它只使用
\u dialogmanager
首先弹出一个
消息对话框,然后弹出另一个

DemoApp
执行此操作的代码如下所示:

private void ShowLayeredDialog()
{
    _dialogManager
        .CreateMessageDialog("Wait 2 secs...", "I'm the 1st dialog", DialogMode.Ok)
        .Show();

    ThreadPool.QueueUserWorkItem(o =>
        {
            Thread.Sleep(2000);
            _dialogManager
                .CreateMessageDialog("Hello again...", "I'm the 2nd dialog", DialogMode.Ok)
                .Show();
        });
}
我试图做一些类似的事情,但没有使用对CreateMessageDialog的方法调用,我想使用他们的
CreateCustomContentDialog()
,它获取一个对象并在模式视图中显示其内容(前提是它的
UIElement

因此,已经调用了
\u dialogManager
让我进入第一个模式视图,我在该视图上创建了一个按钮,使用类似于DemoApp代码的技术生成了一个新的CustomContentDialog:

ThreadPool.QueueUserWorkItem(o => _dialogManager.CreateCustomContentDialog(new SpikePhaseView(), DialogMode.Ok).Show());
不幸的是,我得到了一个异常“调用线程必须是STA,因为许多UI组件在
SpikePhaseView()
的构造函数上都需要它,这是一个普通的用户控件

因此,在研究了这个错误之后,我从设置ApartmentState(ApartmentState.STA)的第二个链接实现了未被接受但投票率较高的解决方案,如下所示:

但是在wpfdialogmanagement框架代码下面的某个地方,我得到了以下错误“调用线程无法访问此对象,因为另一个线程拥有它。”在这段代码中:

public void SetCustomContent(object content)
{
    CustomContent.Content = content;
}
上面,CustomContent(System.Windows.Controls.ContentControl)被设置为my SpikePhaseView对象

编辑

在DemoApp中,他们能够成功地启动两个模式对话框(没有错误)。为什么我不能让一个UserControl(视图)生成另一个,而不让哪个线程设置这个CustomContext对象的内容发生冲突

似乎设置ApartmentState有助于我克服第一个错误,但如果这一切归结为使用Dispatcher,是否有人可以提供一个示例,说明我如何在自己的情况下使用它来启动第二个模式视图的调用


谢谢

除非您真的非常确定自己需要多个UI线程,否则您不希望在应用程序中有多个UI线程。如果您总是需要考虑哪个线程拥有哪个控件,那么事情就会变得非常复杂。如果只有一个UI线程,并且它拥有所有的东西,那么就容易多了

不要试图使您创建的新线程成为STA线程,只需确保从主UI线程创建/访问/显示第二个弹出窗口即可

如果您使用的是C#5.0,这非常简单:

wait
调用将确保方法的其余部分(创建第二个对话框)作为第一个任务的继续运行,并确保它在捕获的SynchronizationContext中运行(在本例中代表UI线程)。最终的结果是,代码不会阻塞后台线程,只保留一个声明范围,执行效果更好,处理错误更好,键入更少,等等

C#4.0实现这一点的方法需要更多的代码:

private void ShowLayeredDialog()
{
    _dialogManager
        .CreateMessageDialog("Wait 2 secs...", "I'm the 1st dialog", DialogMode.Ok)
        .Show();

    Task.Delay(2000).ContinueWith(t =>
    {
        _dialogManager
            .CreateMessageDialog("Hello again...", "I'm the 2nd dialog", DialogMode.Ok)
            .Show();
    }, TaskScheduler.FromCurrentSynchronizationContext());
}

这(或多或少)就是编译器将第一个代码段转换成的内容。

老兄,我懒得读这些。我只想告诉您,无论
[STAThread]
如何,您都不能在WPF中使用多个线程来操作单个UI。尝试其他方法。我在这里看到的警告是,我已经在第一个模态对话框中,我只是尝试从我目前所在的位置启动另一个模态对话框。这会影响你这里的代码吗?还是我应该继续尝试使用异步?@Isaahnelson好吧,如果你想同时与两个表单交互,那意味着你不应该使用模态对话框;您应该使用非模式窗口(并禁用/隐藏您不希望用户在当前时间与之交互的任何窗口),这是一个很好的观点。我之所以使用模态对话框,是因为用户在前台运行“测试”时,需要看到后台发生了什么。尽管如此,我还是应用了你的代码。它是有效的,现在我对它的有效性感到目瞪口呆。我需要阅读更多关于任务或异步的内容。顺便说一句,感谢您在阅读和回答我的帖子时所做的努力。如果你觉得我的帖子很有条理,并且展示了一些研究成果,请也投上一票:)。很难得到分数!
//Consider changing the return type to Task
//if this method is not used as an event handler
private async void ShowLayeredDialog()
{
    _dialogManager
        .CreateMessageDialog("Wait 2 secs...", "I'm the 1st dialog", DialogMode.Ok)
        .Show();

    await Task.Delay(2000);

    _dialogManager
        .CreateMessageDialog("Hello again...", "I'm the 2nd dialog", DialogMode.Ok)
        .Show();
}
private void ShowLayeredDialog()
{
    _dialogManager
        .CreateMessageDialog("Wait 2 secs...", "I'm the 1st dialog", DialogMode.Ok)
        .Show();

    Task.Delay(2000).ContinueWith(t =>
    {
        _dialogManager
            .CreateMessageDialog("Hello again...", "I'm the 2nd dialog", DialogMode.Ok)
            .Show();
    }, TaskScheduler.FromCurrentSynchronizationContext());
}