Мне приходится запускать то, что может быть довольно медленной задачей каждый раз, когда запускается событие SelectionChanged объекта DataGrid.
У меня проблема в том, что мне нужно поддерживать отзывчивость приложения, и если пользователь очень быстро прокручивает с помощью клавиш со стрелками, я не хочу выполнять задачу для каждого элемента. Только предмет, на котором они останавливаются. (Надеюсь, это имеет смысл!)
Я установил очень простой c пример для демонстрации, который отображает список слов в DataGrid, а затем, когда вы прокручиваете их, он добавляет их в ListView .
Это то, что я пробовал до сих пор:
CancellationTokenSource cts;
private bool loading;
private async void dgData_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (loading)
{
cts.Cancel();
return;
}
cts = new CancellationTokenSource();
loading = true;
var x = dgData.SelectedItem.ToString();
await Task.Run(async () =>
{
Thread.Sleep(1000); //Wait a second to see if scrolling quickly...
await ExpensiveProcess(x);
});
loading = false;
}
private async Task ExpensiveProcess(string text)
{
if (cts.IsCancellationRequested)
{
loading = false;
return;
}
await Task.Factory.StartNew(() =>
{
//Expensive process will be done here...
});
Application.Current.Dispatcher.Invoke(() =>
{
lvwItems.Items.Add(text);
});
loading = false;
}
Кажется, это работает в том факте, что если быстро стрелка вниз, он пропускает элементы, но когда я останавливаюсь на одном и хочу его запустить не получается?
Где я ошибаюсь? Это даже лучший подход? Мы будем благодарны за любые советы и будем рады предоставить дополнительную информацию. Заранее спасибо.
ОБНОВЛЕНИЕ:
Я нашел видео на YouTube, в котором предлагалось сделать это, и оно работает так, как я ожидал, поэтому сейчас я собираюсь это, но пока оставляем вопрос открытым для обратной связи.
Создайте таймер, который будет запускать дорогостоящий процесс и установить интервал на что-то низкое, но не слишком медленное, чтобы нажималась клавиша.
var myTimer = new DispatcherTimer();
myTimer.Interval = TimeSpan.FromSeconds(1);
myTimer.Tick += MyTimer_Tick
По событию тика таймера запускает длительный процесс.
private void MyTimer_Tick(object sender, EventArgs e)
{
var x = dgData.SelectedItem.ToString();
Task.Run(async () =>
{
Thread.Sleep(1000); //Needs to be removed
await ExpensiveProcess(x);
});
}
Затем в обычном событии SelectionChanged просто останавливайте и запускайте таймер. Также не забудьте остановить таймер в конце длительного процесса.