且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

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

更新时间:2023-12-06 11:36:46

***的在这种情况下做的事情,就是在你真正调用形式结束,你通知所有的系统你要关闭,这将给你在结束时运行的任何进程的机会。当你再完成并想从另一个线程关闭窗体,您需要使用调用它的UI线程上:

  _hostForm.BeginInvoke(新动作(()=> _hostForm.Close())); 



这可能会更好,如果你很可能永远从另一个线程关闭窗体,实际创建close方法的线程安全的版本;即:

 公共类MyForm的:表格
{
// ...

酒店的公共空间SafeClose()
{
//确保我们的UI线程
如果运行(this.InvokeRequired)
{
的BeginInvoke(新的Action(SafeClose));
的回报;
}

//现在关闭的形式,我们正在对UI线程
关闭所有正在运行();
}

// ...
}

使用这种方法,您可以继续更新的形式和它的用户界面,同时运行的异步操作,然后调用关闭和清理,当你完成。


I'm creating a WPF MVVM application. I have a long process that I want to run in another thread whilst displaying a busy indicator to the user. The problem I have is as follows:

The IsBusy property of the BusyIndicator control is bound to the IsBusy public property of my view model which implements the INotifyPropertyChanged interface. If I run the code below with the Join then the user interface doesn't show the busy indicator as the main UI thread is waiting for the thread "t" to finish. If I remove the join then the Windows Form which is hosting the WPF closes too early. I know that accessing Windows Forms across threads is a big no no but as all I want to do is close the Form I figure the most simple solution is to move _hostForm.Close() to the end of the "DoLongProcess" method. Of course if I do that I get a cross threading exception. Can you please suggest the best approach to take in this situation?

<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();

    }

The best thing to do in this situation, is before you actually invoke the closing of the form, you notify all your systems you are going to close, which will give you the opportunity to run any process at the end. When you are then finished and want to close the form from the other thread, you will need to call it on the UI thread using:

_hostForm.BeginInvoke(new Action(() => _hostForm.Close()));

It might be better, if you are likely to always close the form from another thread, to actually create a thread-safe version of the close method; i.e.:

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();
    }

    // ...
}

Using this sort of approach, you can continue to update the form and it's UI while running asynchronous operations, then invoke the shutdown and cleanup when your done.