I'm currently writing a small Image editing app for the Windows Store (WinRT) using the great WriteableBitmapEx Framework. As functions like .convolute can take a while on WinRT devices (tested on Surface) I'd like to make those requests async so the UI doesn't get blocked and I can show a progress ring.

This is what I've tried so far, an the code itself is working. But the UI still gets blocked and the ring does not show. The code does take about 2 seconds to execute.

// Start Image editing when selection is changed
private async void FilterListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        progressRing.IsActive = true;

        try
        {
            filteredImage = await FilterMethod.imageBW(originalImage, filteredImage);

        }
        catch
        {
            Debug.WriteLine("No items selected");
        }

        mainImage.Source = filteredImage;
        progressRing.IsActive = false;
    }


    // Black & White
    public static async Task<WriteableBitmap> imageBW(WriteableBitmap originalImage, WriteableBitmap filteredImage)
    {
        filteredImage = originalImage.Clone();

        using (filteredImage.GetBitmapContext())
        {
            filteredImage.ForEach(ImageEdit.toGrayscale);
        }

        return filteredImage;
    }


    // Grayscale
    public static Color toGrayscale(int x, int y, Color color)
    {
        byte gray = (byte)(color.R * .3f + color.G * .59f + color.B * .11f);
        Color newColor = Color.FromArgb(255, gray, gray, gray);
        return newColor;
    }
有帮助吗?

解决方案 2

As this kind of image editing seems to be needing to happen on the UI thread, I was able to wrap my code inside a

await Window.Current.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => {}

block, so now it looks like this:

private async void FilterListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    progressRing.IsActive = true;

    try
    {
        await Window.Current.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
        {
            filteredImage = await FilterMethod.imageBW(originalImage, filteredImage);
        }

    }
    catch
    {
        Debug.WriteLine("No items selected");
    }

    mainImage.Source = filteredImage;
    progressRing.IsActive = false;
}

其他提示

OK, as I mentioned, adding async to a method does not make it automagically do things in asynchronous fashion. It just means that the compiler will turn it to a state machine, which makes writing continuations easier.

The easiest way to process it in a background is to wrap the computation in a Task. I'm not quite sure how cross-thread marshalling looks like with bitmaps though:

private async void FilterListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        progressRing.IsActive = true;

        try
        {
            var filteredImage = await Task.Run(() => 
                            {
                                var clonedBitmap = originalImage.Clone();

                                using (clonedBitmap.GetBitmapContext())
                                {
                                   clonedBitmap.ForEach(ImageEdit.toGrayscale);
                                }

                                 return clonedBitmap;
                           });

            mainImage.Source = filteredImage;
        }
        catch
        {
            Debug.WriteLine("No items selected");
        }    

        progressRing.IsActive = false;
    }
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top