Why can't I use CapturePhotoToStreamAsync from

2019-06-13 17:22发布

I have code in a WinForms application where I'm using the WinRT MediaCapture object to take a picture from the device's camera. The code is executed in a System.Threading.Timer call back. I'm trying to move this code into WPF but I'm running into problems. When I try to execute the MediaCapture.CapturePhotoToStreamAsync from the timer's callback in WPF, I receive the following exception:

A first chance exception of type 'System.Exception' occurred in MyAssembly.dll

Additional information: The request is invalid in the current state.

Started

I can create a for loop to execute the method 1000 times and it will work, however, it bombs if the method is called from within a Timer callback.

So to clarify, the code will work in WinForms in a Timer callback The code will bomb in WPF in a Timer callback The code will work in WPF if it's not executed in a timer callback..

I suspect that the issue has something to do with the thread that it's executing on, however, I've tried to use the Dispatcher to no avail.

here is the method that is called:

public async Task CapturePhoto(int width, int height)
    {
        Thread.Sleep(100);
        var jpgProperties = ImageEncodingProperties.CreateJpeg();
        jpgProperties.Width = (uint)width;
        jpgProperties.Height = (uint)height;

        using (var randomAccessStream = new InMemoryRandomAccessStream())
        {
            if (_MediaCaptureManager != null)
            {
                await _MediaCaptureManager.CapturePhotoToStreamAsync(jpgProperties, randomAccessStream);
                randomAccessStream.Seek(0);
                using (var ioStream = randomAccessStream.AsStream())
                {
                    var bitmapImage = new BitmapImage();
                    bitmapImage.BeginInit();
                    bitmapImage.StreamSource = ioStream;
                    bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
                    bitmapImage.EndInit();

                    // copy to byte array
                    int stride = bitmapImage.PixelWidth * 4;
                    byte[] buffer = new byte[stride * bitmapImage.PixelHeight];
                    bitmapImage.CopyPixels(buffer, stride, 0);

                    // create bitmap
                    System.Drawing.Bitmap bitmap =
                        new System.Drawing.Bitmap(
                            bitmapImage.PixelWidth,
                            bitmapImage.PixelHeight,
                            System.Drawing.Imaging.PixelFormat.Format32bppArgb);

                    // lock bitmap data
                    System.Drawing.Imaging.BitmapData bitmapData =
                        bitmap.LockBits(
                            new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height),
                            System.Drawing.Imaging.ImageLockMode.WriteOnly,
                            bitmap.PixelFormat);

                    // copy byte array to bitmap data
                    System.Runtime.InteropServices.Marshal.Copy(
                        buffer, 0, bitmapData.Scan0, buffer.Length);

                    // unlock
                    bitmap.UnlockBits(bitmapData);

                    ImageBrush backgroundBrush = new ImageBrush();
                    backgroundBrush.ImageSource = bitmapImage;

                    System.Windows.Application.Current.Dispatcher.Invoke((Action)(() =>
                    {
                        PreviewPanel.Background = backgroundBrush;
                    }));
                }
            }
        }
    }

I have a small WPF project that I can share via OneDrive if that will help. I don't want to include the URL by default because I'm not sure if that is allowed on SO.

Why can't I use CapturePhotoToStreamAsync from a System.Threading.Timer call back in WPF?

1条回答
戒情不戒烟
2楼-- · 2019-06-13 18:06

You'll need to make sure that the CapturePhotoToStreamAsync is executed on the UI thread.

You should use the DispatcherTimer rather than a Threading.Timer class.

查看更多
登录 后发表回答