In my application, I have a task which runs in the background to perform a long-running job. The user can cancel the job anytime by clicking Stop button. The implementation is as belows:
private CancellationTokenSource m_tokenSource;
private void onStop()
{
    m_tokenSource.Cancel();
}
private void onStart()
{
    m_tokenSource = new CancellationTokenSource();
    AsyncDoingJob();
}
private async void AsyncDoingJob()
{
     await Task.Run(() =>
     {
          for (int imgIdx = 0; imgIdx < m_ListImageFiles.Count; imgIdx++)
          {
                if (m_tokenSource.IsCancellationRequested) // Check if the user clicks Stop button
                {
                    return;
                }
                byte[] imageData = File.ReadAllBytes(m_ListImageFiles[imgIdx]); // Load image in background
                Application.Current.Dispatcher.Invoke(() =>
                {
                        m_model.Image = CreateImage(imageData);
                        m_model.Image.Freeze();                      
                        MyImage = m_model.Image;   // This calls NotifyPropertyChanged() to update the image on GUI                     
                }
                // Access to m_model.Image for some reason
          }
     }, m_tokenSource.Token);
}
The problem: Sometimes, while the job is being performed, GUI stop updating (hanging). And if I try to manipulate the GUI, an exception happens: System.Runtime.InteropServices.COMException: UCEERR_RENDERTHREADFAILURE (Exception from HRESULT: 0x88980406)
I found a similar problem reported here: WPF render thread failures
Do you know what it is and how to fix this? Is there anything wrong with my source code?
I can't tell why you get that error. You may however try an implementation like this:
private bool continueLoading;
private void OnStop()
{
    continueLoading = false;
}
private async Task OnStart()
{
    continueLoading = true;
    await LoadImagesAsync(m_ListImageFiles);
}
private async Task LoadImagesAsync(IEnumerable<string> imageFiles)
{
    foreach (var imageFile in imageFiles)
    {
        if (!continueLoading)
        {
            break;
        }
        Image = await LoadImageAsync(imageFile); // assignment in UI thread
        // do more async calls here if necessary
    }
}
private static Task<ImageSource> LoadImageAsync(string fileName)
{
    return Task.Run(() =>
    {
        using (var stream = File.OpenRead(fileName))
        {
            return LoadImage(stream);
        }
    });
}
private static ImageSource LoadImage(Stream stream)
{
    return BitmapFrame.Create(
        stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
    // Alternative:
    //
    // var bitmapImage = new BitmapImage();
    // bitmapImage.BeginInit();
    // bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
    // bitmapImage.StreamSource = stream;
    // bitmapImage.EndInit();
    // bitmapImage.Freeze();
    // return bitmapImage;
}
User contributions licensed under CC BY-SA 3.0