UWP How to cancel a file search

Arsen Kovalchuk 0 Reputation points
2024-09-10T15:14:33.9233333+00:00

I have a code to search for files in a user's selected folder, the file search takes some time and I need to be able to cancel it if the user changes the folder

QueryOptions options = new QueryOptions(CommonFileQuery.OrderByName, filesExtensions) { FolderDepth = FolderDepth.Deep };
   StorageFileQueryResult queryresult = folder.CreateFileQueryWithOptions(options);
   var files = await queryresult.GetFilesAsync();

I tried to use the CancellationToken token for this, but it doesn't work properly.

 var files = await queryResult.GetFilesAsync().AsTask(cancellationTokenSource.Token);
Universal Windows Platform (UWP)
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,905 questions
{count} votes

1 answer

Sort by: Most helpful
  1. youzeliang 735 Reputation points
    2024-09-27T06:43:09.5233333+00:00

    To properly implement cancellation for your file search in a user-selected folder, you are correct in using CancellationToken. However, the issue is that the GetFilesAsync() method you’re using with the StorageFileQueryResult doesn’t inherently support cancellation.

    The GetFilesAsync() method does not take a CancellationToken as a parameter directly, so calling .AsTask(cancellationTokenSource.Token) on it doesn’t actually cancel the operation, as the underlying API does not support it natively.

    Workaround for Cancellation

    To handle cancellation more effectively, you can:

    1.	Manually manage the cancellation by splitting the operation into smaller chunks.
    
    2.	Check for cancellation after each chunk and throw a TaskCanceledException if cancellation is requested.
    

    Here’s how you could modify your code:

    Step-by-Step Implementation

    1.	Set Up a Loop with Batching: Instead of fetching all files at once, fetch files in batches, allowing cancellation checks between batches.
    
    2.	Check CancellationToken Regularly: Regularly check the cancellation token within the loop to see if the operation should stop.
    

    Here is an example implementation:

    public async Task<IReadOnlyList<StorageFile>> SearchFilesAsync(StorageFolder folder, string[] filesExtensions, CancellationToken cancellationToken)

    {

    QueryOptions options = new QueryOptions(CommonFileQuery.OrderByName, filesExtensions)
    
    {
    
        FolderDepth = FolderDepth.Deep
    
    };
    
    StorageFileQueryResult queryResult = folder.CreateFileQueryWithOptions(options);
    
    uint index = 0;
    
    uint stepSize = 50; // Retrieve files in batches to allow for cancellation
    
    List<StorageFile> allFiles = new List<StorageFile>();
    
    while (true)
    
    {
    
        // Fetch files in batches
    
        var files = await queryResult.GetFilesAsync(index, stepSize);
    
        // Check for cancellation
    
        cancellationToken.ThrowIfCancellationRequested();
    
        // Add files to the list
    
        allFiles.AddRange(files);
    
        // Break the loop if there are no more files to retrieve
    
        if (files.Count < stepSize)
    
        {
    
            break;
    
        }
    
        // Increment the index to get the next batch of files
    
        index += stepSize;
    
    }
    
    return allFiles;
    

    }

    How It Works:

    •	Batching: The method fetches files in batches of stepSize (e.g., 50). This way, the search operation doesn’t lock up entirely and gives you the ability to check for cancellation between the batches.
    
    •	Cancellation Checking: After each batch retrieval, cancellationToken.ThrowIfCancellationRequested() is called to check if the operation was cancelled. If it has been, a TaskCanceledException is thrown, and the search operation stops.
    

    Usage Example:

    CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();

    try

    {

    // Start the search operation with a cancellation token
    
    var files = await SearchFilesAsync(folder, filesExtensions, cancellationTokenSource.Token);
    
    
    
    // Do something with the files
    

    }

    catch (TaskCanceledException)

    {

    // Handle the cancellation, perhaps notify the user
    
    Console.WriteLine("File search operation was canceled.");
    

    }

    // To cancel the operation, simply call:

    cancellationTokenSource.Cancel();

    Key Points:

    •	Graceful Cancellation: With the cancellationToken.ThrowIfCancellationRequested(), you can gracefully stop the operation whenever the user decides to cancel.
    
    •	Batch Processing: The loop processes the files in chunks, so you aren’t loading everything at once, which also improves responsiveness.
    

    This approach ensures that your file search can be cancelled mid-operation when the user changes the folder or requests cancellation.

    If my answer is helpful to you, you can adopt it, thank you!

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.