使用 cancellationToken 取消搜索
Canceling search using a cancellationToken
我的挑战是一个相当普遍的挑战,我有一个人口稠密的树视图,我想过滤。为此,我想要一个文本框,用户可以在其过滤文本中输入该文本框,并且在树视图被过滤后显示其 header.
中具有该特定过滤文本的节点
所以我选择做的是有一个文本框,然后有一个文本更改事件,在它开始过滤过程之前有一个延迟,现在很明显,如果过滤文本在延迟完成之前发生变化,我想取消该过程并使用新的 fitler 文本开始新的过程。
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Controls;
namespace pav.skillsToCompetenciesMapper.Views
{
public partial class MapSkillsPage : Page
{
CancellationTokenSource cts;
private async void Search_TEXTBOX_TextChanged(object sender, TextChangedEventArgs e)
{
if (cts != null) cts.Cancel();
var searchText = Search_TEXTBOX.Text;
try
{
using (cts = cts ?? new CancellationTokenSource())
await Task.Delay(3000, cts.Token).ContinueWith(tr =>
{
var st = searchText;
//Do search here
}, TaskContinuationOptions.NotOnCanceled);
}
catch (OperationCanceledException) { }
finally { cts = null; }
}
}
}
现在上面的方法似乎对我有用,我只是担心这个 try catch 解决方案有点笨拙,看起来好像我应该能够使用 TaskContinuation.OnlyOnCanceled 来避免使用尝试抓住逻辑。对我来说就像代码的味道,但这是旁注。
我真正的问题出现在我尝试实际搜索 Treeview 时,上面的 "Do Search Here" 评论是
foreach (TreeViewItem category in Abilities_TreeView.Items)
foreach (DragableTreeViewItem ability in category.Items)
if (!ability.Header.ToString().Contains(filterText))
ability.Visibility = Visibility.Hidden;
如能提供任何帮助,我将不胜感激,我怀疑这与尝试从后台线程访问 UI 线程有关,但我不能 100% 确定我是否我叫对了树。
如果您不想处理 OperationCanceledException
,您可以使用仅接受继续操作的 ContinueWith
方法的重载并检查 IsCanceled
的值属性 在此操作中:
try
{
using (cts = cts ?? new CancellationTokenSource())
await Task.Delay(3000, cts.Token).ContinueWith(tr =>
{
if (!tr.IsCanceled)
{
var st = searchText;
//Do search here
}
});
}
finally { cts = null; }
thanks, sorry i was a bit trigger happy, and didn't finish asking my question
除了最初创建它的调度程序线程之外,您无法从任何其他线程访问 TreeView
,但您可以通过使用重载确保继续操作将在此线程上执行接受 TaskScheduler
:
await Task.Delay(3000, cts.Token).ContinueWith(tr =>
{
if (!tr.IsCanceled)
{
var st = searchText;
//Do search here
}
}, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
我的挑战是一个相当普遍的挑战,我有一个人口稠密的树视图,我想过滤。为此,我想要一个文本框,用户可以在其过滤文本中输入该文本框,并且在树视图被过滤后显示其 header.
中具有该特定过滤文本的节点所以我选择做的是有一个文本框,然后有一个文本更改事件,在它开始过滤过程之前有一个延迟,现在很明显,如果过滤文本在延迟完成之前发生变化,我想取消该过程并使用新的 fitler 文本开始新的过程。
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Controls;
namespace pav.skillsToCompetenciesMapper.Views
{
public partial class MapSkillsPage : Page
{
CancellationTokenSource cts;
private async void Search_TEXTBOX_TextChanged(object sender, TextChangedEventArgs e)
{
if (cts != null) cts.Cancel();
var searchText = Search_TEXTBOX.Text;
try
{
using (cts = cts ?? new CancellationTokenSource())
await Task.Delay(3000, cts.Token).ContinueWith(tr =>
{
var st = searchText;
//Do search here
}, TaskContinuationOptions.NotOnCanceled);
}
catch (OperationCanceledException) { }
finally { cts = null; }
}
}
}
现在上面的方法似乎对我有用,我只是担心这个 try catch 解决方案有点笨拙,看起来好像我应该能够使用 TaskContinuation.OnlyOnCanceled 来避免使用尝试抓住逻辑。对我来说就像代码的味道,但这是旁注。
我真正的问题出现在我尝试实际搜索 Treeview 时,上面的 "Do Search Here" 评论是
foreach (TreeViewItem category in Abilities_TreeView.Items)
foreach (DragableTreeViewItem ability in category.Items)
if (!ability.Header.ToString().Contains(filterText))
ability.Visibility = Visibility.Hidden;
如能提供任何帮助,我将不胜感激,我怀疑这与尝试从后台线程访问 UI 线程有关,但我不能 100% 确定我是否我叫对了树。
如果您不想处理 OperationCanceledException
,您可以使用仅接受继续操作的 ContinueWith
方法的重载并检查 IsCanceled
的值属性 在此操作中:
try
{
using (cts = cts ?? new CancellationTokenSource())
await Task.Delay(3000, cts.Token).ContinueWith(tr =>
{
if (!tr.IsCanceled)
{
var st = searchText;
//Do search here
}
});
}
finally { cts = null; }
thanks, sorry i was a bit trigger happy, and didn't finish asking my question
除了最初创建它的调度程序线程之外,您无法从任何其他线程访问 TreeView
,但您可以通过使用重载确保继续操作将在此线程上执行接受 TaskScheduler
:
await Task.Delay(3000, cts.Token).ContinueWith(tr =>
{
if (!tr.IsCanceled)
{
var st = searchText;
//Do search here
}
}, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());