次の方法で実行するバックグラウンド タスクがあります。
これは、テキスト ボックスのテキスト変更イベントに付随する動作です。
私が望むのは、テキストが変更されてから再度変更された場合、2回目の変更で前のタスクがまだ実行されているかどうかを確認し、そうであれば停止して最新のタスクを続行することです。
public class FindTextChangedBehavior : Behavior<TextBox>
{
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.TextChanged += OnTextChanged;
}
protected override void OnDetaching()
{
AssociatedObject.TextChanged -= OnTextChanged;
base.OnDetaching();
}
private void OnTextChanged(object sender, TextChangedEventArgs args)
{
var textBox = (sender as TextBox);
if (textBox != null)
{
Task.Factory.StartNew(() =>
{
//Do text search on object properties within a DataGrid
//and populate temporary ObservableCollection with items.
ClassPropTextSearch.init(itemType, columnBoundProperties);
if (itemsSource != null)
{
foreach (object o in itemsSource)
{
if (ClassPropTextSearch.Match(o, searchValue))
{
tempItems.Add(o);
}
}
}
//Copy temporary collection to UI bound ObservableCollection
//on UI thread
Application.Current.Dispatcher.Invoke(new Action(() => MyClass.Instance.SearchMarkers = tempItems));
});
}
}
[編集] 私はこれをまだテストしていません。
CancellationTokenSource CancellationTokenSource = new CancellationTokenSource();
private void OnTextChanged(object sender, TextChangedEventArgs args)
{
var newCts = new CancellationTokenSource();
var oldCts = Interlocked.Exchange(ref this.CancellationTokenSource, newCts);
if (oldCts != null)
{
oldCts.Cancel();
}
var cancellationToken = newCts.Token;
var textBox = (sender as TextBox);
if (textBox != null)
{
ObservableCollection<Object> tempItems = new ObservableCollection<Object>();
var ui = TaskScheduler.FromCurrentSynchronizationContext();
var search = Task.Factory.StartNew(() =>
{
ClassPropTextSearch.init(itemType, columnBoundProperties);
if (itemsSource != null)
{
foreach (object o in itemsSource)
{
cancellationToken.ThrowIfCancellationRequested();
if (ClassPropTextSearch.Match(o, searchValue))
{
tempItems.Add(o);
}
}
}
}, cancellationToken);
//Still to be considered.
//If it gets to here and it is still updating the UI then
//what to do, upon SearchMarkers being set below do I cancel
//or wait until it is done and continue to update again???
var displaySearchResults = search.ContinueWith(resultTask =>
MyClass.Instance.SearchMarkers = tempItems,
CancellationToken.None,
TaskContinuationOptions.OnlyOnRanToCompletion,
ui);
}
}