WPF非阻塞UI弹出窗口

时间:2019-03-10 17:23:21

标签: c# wpf multithreading

在Office加载项中,我需要调用WPF,该WPF执行的功能可能会超时,但是我希望UI能够响应以允许用户单击“取消/关闭”按钮。 到目前为止,我的代码如下:

// From the Ribbon
var f = new Forms.CheckConnectivityPopup();
f.doneEvent.WaitOne();

// Get the status from the popup or null if the operation was cancelled
var status = f.status;
if(status != null)

// Continue the execution
--------------------------------
public partial class CheckConnectivityPopup : MetroWindow
{
    public readonly BackgroundWorker worker = new BackgroundWorker();
    public AutoResetEvent doneEvent = new AutoResetEvent(false);
    public Status status = null;

    public CheckConnectivityPopup()
    {
        InitializeComponent();
        this.Show();
        worker.DoWork += worker_DoWork;
        worker.RunWorkerCompleted += worker_RunWorkerCompleted;
        worker.RunWorkerAsync();
    }    
    private void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        // displayAndCheck();
        status = CheckStatus();
        Thread.Sleep(10000); // to simulate the time
    }
    private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        doneEvent.Set();
        this.Close();
    }
}

到目前为止,弹出窗口一直处于冻结状态,直到睡眠期结束。

1 个答案:

答案 0 :(得分:1)

WaitOne()阻止当前线程。您可以将AutoResetEvent替换为SemaphoreSlim

public partial class CheckConnectivityPopup : MetroWindow
{
    public readonly BackgroundWorker worker = new BackgroundWorker();
    public SemaphoreSlim doneEvent = new SemaphoreSlim(0, 1);
    public Status status = null;

    public CheckConnectivityPopup()
    {
        InitializeComponent();
        this.Show();
        worker.DoWork += worker_DoWork;
        worker.RunWorkerCompleted += worker_RunWorkerCompleted;
        worker.RunWorkerAsync();
    }
    private void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        //displayAndCheck();
        status = CheckStatus();
        Thread.Sleep(10000); // to simulate the time
    }
    private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        doneEvent.Release();
        this.Close();
    }
}

...您可以异步等待:

var f = new Forms.CheckConnectivityPopup();
await f.doneEvent.WaitAsync();

为使您能够等待WaitAsync()方法,必须将创建CheckConnectivityPopup实例的方法标记为async

void async YourMethod() { ... }

如果由于某种原因这不是一个选择,则可以改用ContinueWith方法:

var f = new Forms.CheckConnectivityPopup();
f.doneEvent.WaitAsync().ContinueWith(_ => 
{
    var status = f.status;
    if (status != null)
    {
        //...
    }
});