C#WPF取消异步功能

时间:2015-11-12 16:25:59

标签: c# wpf async-await cancel-button cancellationtokensource

我仍然对C#WPF很新鲜,并且一直在使用异步功能。这就是我所拥有的

private void btnGetAccount(object sender, RoutedEventArgs e) {
    try {
        var found = Task<bool>.Factory.StartNew(() => SearchForAccount());
        await found;
    }
    catch .... 
}

private bool SearchForAccount() {
    Dispatcher.Invoke(() => { //UI Updates }
    AnotherFunctionCall();
    return true;
}

问题是,有时SearchForAccount函数会超时。因为没有错误被抛出,我还没有弄明白是什么导致了它。我想实现一个允许此函数调用取消的按钮。我已经尝试过使用CancellationTokenSource,但它似乎并没有按照我的方式工作。

非常感谢任何帮助或建议。

谢谢! RealityShift

编辑:

这是我尝试使用CancellationToken

private void btnGetAccount(object sender, RoutedEventArgs e) {
    CancellationTokenSource cts = new CancellationTokenSource();

    try {
        cts.CancelAfter(200);
        var found = Task<bool>.Factory.StartNew(() => SearchForAccount(), cts.Token);
        await found;
    }
    catch (OperationCanceledException ex) {
        SetStatusLabel("Cancel done.");
    }
}

我也试过这样的事情(不能完全记住,现在还没有撤消历史记录):

private void btnGetAccount(object sender, RoutedEventArgs e) {
    CancellationTokenSource cts = new CancellationTokenSource();
    CancellationToken token = cts.Token;

    try {
        cts.CancelAfter(200);
        var found = Task<bool>.Factory.StartNew(() => SearchForAccount(token), cts.Token);
        await found;
    }
    catch (OperationCanceledException ex) {
        SetStatusLabel("Cancel done.");
    }
}

我将令牌传递给了该功能,但我不记得我对该功能做了什么。在这两种情况下,在SearchForAccount函数调用返回之后(如果它返回),取消没有任何反应。如果它没有返回,那么它就会卡住,这正是我想要取消按钮的原因。

快速破败: 计划启动。 用户可以输入用户名并点击搜索。 然后,搜索将搜索域中是否存在该帐户以及该帐户的一些详细信息。 搜索完成后,结果将发布到数据网格。

问题: 在进行搜索时,有时(很少)它将继续无限期搜索并且永远不会返回。返回超时消息的东西会很棒。

2 个答案:

答案 0 :(得分:0)

我只知道如何取消执行Task。可能会有所帮助。

CancellationTokenSource cts = new CancellationTokenSource();
CancellationToken token = cts.Token;

Task myTask = Task.Factory.StartNew(() =>
{
    while (true)
    {
        token.ThrowIfCancellationRequested();
        // loop's body
    }
}, token);

// cancellation
cts.Cancel();

CancellationTokenSource cts = new CancellationTokenSource();
CancellationToken token = cts.Token;

Task myTask = Task.Factory.StartNew(() =>
{
    while (true)
    {
        if(token.IsCancellationRequested)
        {
            return;
        }
       // loop's body
    }
}, token);

// cancellation
cancelToken.Cancel(false);

执行模式如下所示:

//property of the class
private readonly CancellationTokenSource cts = new CancellationTokenSource();

private void btnDo(object sender, RoutedEventArgs e) {
    var found = Task.Factory.StartNew(() =>
    {
        try
        {
            while (true)
            {
                cts.Token.ThrowIfCancellationRequested();
                //loop's body
            }
        }
        catch (OperationCanceledException ex)
        {
            SetStatusLabel("Cancel done.");
        }
    }, cts.Token);
}

private void btnCancel(object sender, RoutedEventArgs e) {
    //cancelling
    cts.Cancel();
}

答案 1 :(得分:0)

您应该分离获取数据和更新UI的逻辑,在您使用调度程序调用时,您正在冻结UI线程。使用更类似的东西。

private CancellationTokenSource cts;

private void btnGetAccount(object sender, RoutedEventArgs e) 
{
    try
    {
        if (cts != null)
        {
            cts.Cancel();
        }

        cts = new CancellationTokenSource();
        var token = cts.Token;

        Task.Factory.StartNew(
            () =>
                {
                    var found = SearchForAccount();

                    if (!token.IsCancellationRequested)
                    {
                        Dispatcher.Invoke(
                            () =>
                                {
                                    SetStatusLabel(found ? "Found" : "Not found");
                                });
                    }
                },
                token);
    }
    catch (OperationCanceledException ex)
    {
        SetStatusLabel("Cancel done.");
    }
}