简体   繁体   English

C#WPF取消异步功能

[英]C# WPF Cancellation of async function

I'm still fairly fresh to C# WPF and have been working with async functions. 我对C#WPF还是很新鲜,并且一直在使用异步功能。 This is what I have 这就是我所拥有的

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

and

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

The issue is, sometimes the SearchForAccount function times out. 问题是,有时SearchForAccount函数会超时。 I haven't figured out what is causing it since no errors get thrown. 我没有弄清楚是什么原因造成的,因为没有引发任何错误。 I would like to implement a button that allows this function call to cancel. 我想实现一个按钮,该按钮可以取消此函数调用。 I've tried messing with CancellationTokenSource but it doesn't seem to work the way I am doing it. 我曾尝试将CancellationTokenSource弄乱,但它似乎无法按照我的方式工作。

Any help or suggestions would be greatly appreciated. 任何帮助或建议,将不胜感激。

Thanks! 谢谢! RealityShift 现实转变

EDIT: 编辑:

Here is my attempt with CancellationToken 这是我对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.");
    }
}

I also tried something like this (can't remember exactly and it's not in undo history now): 我也尝试过这样的事情(不记得确切了,现在不在撤消历史中):

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.");
    }
}

I passed the token into the function but I don't remember what I did with the function. 我将令牌传递给函数,但是我不记得我对函数做了什么。 In both cases, nothing happens for the cancel until after the SearchForAccount function call returns (if it returns). 在这两种情况下,直到SearchForAccount函数调用返回(如果返回)之后,取消操作都不会发生。 If it doesn't return, then it's stuck which is exactly why I want a cancel button. 如果没有返回,则说明卡住了,这正是我想要取消按钮的原因。

Quick run-down: Program launches. 快速淘汰:程序启动。 User can type in a username and hit search. 用户可以输入用户名并点击搜索。 The search will then search to see if the account exists on the domain and some details on the account. 然后搜索将搜索以查看该帐户在域中是否存在以及该帐户的一些详细信息。 After the search is done, the results are posted to a data grid. 搜索完成后,结果将发布到数据网格中。

The problem: When hitting search, sometimes (rarely) it will continue to search indefinitely and never return. 问题:点击搜索时,有时(很少)它将继续无限期搜索,并且永不返回。 Something to return a timeout message would be great. 返回超时消息的东西很棒。

I only know how you can cancel executing Task . 我只知道如何取消执行Task May be it will be helpful. 可能会有所帮助。

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

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

// cancellation
cts.Cancel();

or 要么

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

The schema of execution looks like this: 执行模式如下所示:

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

You should separate the logic of getting the data and updating the UI, at the moment you use the dispatcher invoke you are freezing the UI thread. 您应该分离获取数据和更新UI的逻辑,在使用分派器调用时,您将冻结UI线程。 Use something more similar to this. 使用与此类似的内容。

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.");
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM