4

So I have a combobox on my UI that on SelectionChanged it asynchronously goes off to a web service to pull back some information to be displayed on the UI (using the new C#5 async/await keywords). What I'm looking to do is cancel the current async request before sending a new one; for example if the user uses the keyboard to quickly cycle through all of the combobox items, the SelectionChanged event could fire multiple times (generating multiple async requests) before even the first async request returns.

So my async function that gets called from the combobox's SelectionChanged event looks like this:

public async Task<Connections> ConnectionsAsync()
{
    return await Task.Factory.StartNew(() => Connections, _cancellationTokenSource.Token);
}

Where Connections is a property that goes off and hits the web service. So because the CancellationTokenSource cannot be reused once cancelled, I'm thinking of doing this:

public async Task<Connections> ConnectionsAsync()
{
    _cancellationTokenSource.Cancel();
    _cancellationTokenSource = new CancellationTokenSource();
    return await Task.Factory.StartNew(() => Connections, _cancellationTokenSource.Token);
}

The problem though is that sometimes I will be calling Cancel() when there is no async command running (e.g. the first time this function is called); so if I hookup any cancellation event handlers they will get called, even before I have made an async request.

Is there anyway to check if an async request is already running? Other than me doing something like:

public async Task<Connections> ConnectionsAsync()
{
    if (_runningAsyncCommand)
        _cancellationTokenSource.Cancel();
    _cancellationTokenSource = new CancellationTokenSource();
    _runningAsyncCommand = true;
    return await Task.Factory.StartNew(() => Connections, _cancellationTokenSource.Token);
    _runningAsyncCommand = false;
}

I have a few async functions that all use the same CancellationTokenSource, so I would have to implement this "plumbing" in all of those functions. Is this the best approach? Or is there a better way?

Also, if I expose _cancellationTokenSource publically so that other classes can register cancellation delegates with it, what is the best way to "transfer" these delegates over to the new CancellationTokenSource, since I'm creating a new one every time?

Thanks in advance!

4

1 に答える 1

2

ReactiveExtensionsのために天国で行われた試合のように見えます。タスクを作成する前にコンボボックスからのイベントを監視するときに経過する必要のあるスロットル時間(たとえば300mS)を定義します

TextBoxの変更イベントをサブスクライブするコードスニペットですが、次のようなアイデアが得られます。

var input (from evt in Observable.FromEvent<EventArgs>(txt, "TextChanged")
select ((TextBox)evt.Sender).Text)
.Throttle(TimeSpan.FromSeconds(1))
.DistinctUntilChanged();

using (input.Subscribe(inp => Console.WriteLine("You wrote: " + inp)))
{
  // Do stuff
}
于 2012-07-07T16:57:54.783 に答える