1

我对 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 但它似乎不像我这样做的那样工作。

任何帮助或建议将不胜感激。

谢谢!现实转变

编辑:

这是我对 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 函数调用返回(如果它返回)之前,取消不会发生任何事情。如果它没有返回,那么它就卡住了,这正是我想要一个取消按钮的原因。

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

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

4

2 回答 2

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();
}
于 2015-11-12T17:07:01.870 回答
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.");
    }
}
于 2015-11-13T09:14:54.650 回答