C#如何从另一个线程关闭主UI线程上的Windows窗体

dio*_*001 2 c# wpf multithreading

我正在创建一个WPF MVVM应用程序.我有一个漫长的过程,我想在另一个线程中运行,同时向用户显示忙碌指示器.我遇到的问题如下:

BusyIndi​​cator控件的IsBusy属性绑定到我的视图模型的IsBusy公共属性,该属性实现了INotifyPropertyChanged接口.如果我使用Join运行下面的代码,那么用户界面不会显示忙指示符,因为主UI线程正在等待线程"t"完成.如果我删除了连接,那么托管WPF的Windows窗体会过早关闭.我知道跨线程访问Windows窗体是一个很大的问题,但是我想要做的就是关闭Form I,最简单的解决方案是将_hostForm.Close()移动到"DoLongProcess"方法的末尾.当然,如果我这样做,我会得到一个交叉线程异常.您能否建议采取最佳方法来应对这种情况?

<extToolkit:BusyIndicator IsBusy="{Binding Path=IsBusy}" >
    <!-- Some controls here -->
</extToolkit:BusyIndicator>

private void DoSomethingInteresting() { 

        //  Set the IsBusy property to true which fires the 
        //  notify property changed event
        IsBusy = true;

        //  Do something that takes a long time
        Thread t = new Thread(DoLongProcess);
        t.Start();
        t.Join();

        //  We're done. Close the Windows Form
        IsBusy = false;
        _hostForm.Close();

    }
Run Code Online (Sandbox Code Playgroud)

Sam*_*ade 8

在这种情况下最好的做法是,在您实际调用表单关闭之前,通知您要关闭的所有系统,这将使您有机会在最后运行任何进程.当您完成并希望从另一个线程关闭表单时,您需要使用以下命令在UI线程上调用它:

_hostForm.BeginInvoke(new Action(() => _hostForm.Close()));
Run Code Online (Sandbox Code Playgroud)

如果您可能总是从另一个线程关闭表单,实际创建close方法的线程安全版本可能会更好; 即:

public class MyForm : Form
{
    // ...

    public void SafeClose()
    {
        // Make sure we're running on the UI thread
        if (this.InvokeRequired)
        {
            BeginInvoke(new Action(SafeClose));
            return;
        }

        // Close the form now that we're running on the UI thread
        Close();
    }

    // ...
}
Run Code Online (Sandbox Code Playgroud)

使用这种方法,您可以在运行异步操作时继续更新表单及其UI,然后在完成后调用shutdown和cleanup.