使用另一个线程

时间:2015-05-07 12:47:20

标签: c# wpf multithreading

我正在尝试在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.

2 个答案:

答案 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

(注意:这并不是说这是一个通常有用/推荐的设计模式。事实上,它经常会导致比它解决的更多问题。但是,它肯定是你可以选择做。)