Отмена поиска с помощью cancellationToken - PullRequest
0 голосов
/ 06 сентября 2018

моя задача довольно распространенная, у меня густонаселенное дерево, которое я хочу отфильтровать. Для этого я хочу иметь текстовое поле, которое пользователь вводит в свой текст фильтра и после того, как древовидное представление отфильтровано, чтобы показать узлы с этим конкретным текстом фильтра в заголовке.

так что я решил использовать текстовое поле с событием изменения текста, которое имеет задержку до начала процесса фильтрации, теперь, очевидно, если текст фильтра изменяется до того, как задержка заканчивается, я хочу отменить обработайте и начните новый с новым текстом соответствия.

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 для логики. , для меня это просто запах кода, но это примечание.

Моя настоящая проблема возникает, когда я пытаюсь действительно выполнить поиск в древовидной структуре, например, где приведенный выше комментарий «Выполнить поиск здесь» равен

foreach (TreeViewItem category in Abilities_TreeView.Items)
    foreach (DragableTreeViewItem ability in category.Items)
        if (!ability.Header.ToString().Contains(filterText))
            ability.Visibility = Visibility.Hidden;

Любая помощь по этому вопросу будет принята с благодарностью, я подозреваю, что это как-то связано с попыткой доступа к потоку пользовательского интерфейса из фонового потока, но я не уверен на 100%, если я лаю нужное дерево .

1 Ответ

0 голосов
/ 06 сентября 2018

Если вы не хотите обрабатывать 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());
...