我正在尝试在WPF中创建一个简单的应用程序,它将在一个奇怪的行为中打开一个新窗口。
ArrayList formArray = new ArrayList();
Thread th;
Window1 vd;
public void Start()
{
vd = new Window1();
formArray.Add(vd);
vd.ShowDialog();
}
public void StartCall()
{
th = new Thread(new ThreadStart(Start));
th.SetApartmentState(ApartmentState.STA);
th.Start();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
StartCall();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
((Window1)(formArray[0])).Show();
}
Window1代码是
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
e.Cancel = true;
this.Hide();
}
尝试再次打开时,只会抛出错误The calling thread cannot access this object because a different thread owns it
。
当尝试使用调度程序时...调用...所有这些事情都没有帮助。 为了使它更奇怪,这个相同的代码在Windows窗体应用程序中工作。
也许它与这条线有关? th.SetApartmentState(ApartmentState.STA);
?
可能是这些人,但是如果我没有添加它,它也会因为错误而失败
Additional information: The calling thread must be STA, because many UI components require this.
答案 0 :(得分:1)
编辑: 在线程上添加了对调度程序运行的强制。 我还添加了一个Display方法来显示对话框,具体取决于正在调用的调度程序。希望有所帮助!
此外,如此处所述:Dispatcher.Run
完成后,您应该关闭相应线程的调度程序。
主窗口:
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
StartCall();
}
ArrayList formArray = new ArrayList();
Window1 vd;
Thread th;
public void Start()
{
vd = new Window1();
formArray.Add(vd);
vd.ShowDialog();
System.Windows.Threading.Dispatcher.Run(); //ok this is magic
}
public void StartCall()
{
th = new Thread(new ThreadStart(Start));
th.SetApartmentState(ApartmentState.STA);
th.Start();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
StartCall();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
((Window1)(formArray[0])).Display();
}
窗口1:
void Window1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
e.Cancel = true;
this.Hide();
}
public void Display()
{
if (!Dispatcher.CheckAccess())
{
Dispatcher.BeginInvoke((Action)Display);
return;
}
this.Show();
}
答案 1 :(得分:0)
你不能从你创建的线程以外的线程上调用窗口上的.Show
(这基本上就是错误消息告诉你的内容!)。幸运的是,正如您所建议的那样,这就是调度程序的用途:将调用编组到正确的线程上。但你必须使用正确的调度员来完成工作!
WPF中的每个控件(包括一个Window)都有一个.Dispatcher
属性,可以获取该控件的线程的Dispatcher 。我的猜测是,当您尝试重新打开对话框时,您正在使用主窗口中的那个 - 这是错误的。相反,如果你在Button_Click
中使用它,你会有更多的运气:
var window = (Window1)formArray[0];
window.Dispatcher.Invoke(window.Show); // note: use the dispatcher that belongs to the window you're calling
(注意:这并不是说这是一个通常有用/推荐的设计模式。事实上,它经常会导致比它解决的更多问题。但是,它肯定是你可以选择做。)