使用cancelToken取消搜索

时间:2018-09-06 14:22:11

标签: c# wpf task-parallel-library

我的挑战很普遍,我有一个要过滤的人口稠密的树状视图。为此,我想要一个用户在其过滤器文本中输入的文本框,并在过滤树视图以显示其标题中具有该特定过滤器文本的节点之后。

所以我选择做的是创建一个文本框,该文本框然后具有一个文本更改事件,该事件在开始过滤过程之前会延迟,现在很明显,如果过滤器文本在延迟结束之前发生更改,我想取消处理并使用新的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以避免将try catch用作逻辑。对我来说似乎有点代码臭味,但这是一个旁注。

当我尝试实际搜索Treeview时出现了我的真正问题,因此上面的“在这里搜索”注释位于

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%是否在树立正确的树

1 个答案:

答案 0 :(得分:1)

如果您不想处理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; }
  

谢谢,对不起,我有点高兴,还没有完成问我的问题

除了最初在其上创建的调度程序线程之外,您无法从任何其他线程访问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());