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