为什么我不能在 WPF 中使用 System.Threading.Timer 回调中的 CapturePhotoToStreamAsync?

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

我在 WinForms 应用程序中有代码,我在其中使用 WinRT MediaCapture 对象从设备的相机拍摄照片。代码在 System.Threading.Timer 回调中执行。我正在尝试将此代码移动到 WPF 中,但我 运行 遇到了问题。当我尝试从 WPF 中的计时器回调执行 MediaCapture.CapturePhotoToStreamAsync 时,我收到以下异常:

'System.Exception' 类型的第一次机会异常发生在 MyAssembly.dll

附加信息:请求在当前状态下无效。

开始

我可以创建一个 for 循环来执行该方法 1000 次,它会起作用,但是,如果从 Timer 回调中调用该方法,它就会崩溃。

所以澄清一下,代码将在 WinForms 中的计时器回调中运行 该代码将在 WPF 中的计时器回调中轰炸 如果不在计时器回调中执行,代码将在 WPF 中工作..

我怀疑问题与它正在执行的线程有关,但是,我尝试使用 Dispatcher 无济于事。

这里是被调用的方法:

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;
                    }));
                }
            }
        }
    }

我有一个小型 WPF 项目,如果有帮助,我可以通过 OneDrive 共享它。我不想默认包含 URL,因为我不确定 SO 是否允许这样做。

为什么我不能在 WPF 中使用 System.Threading.Timer 回调中的 CapturePhotoToStreamAsync?

您需要确保 CapturePhotoToStreamAsync 在 UI 线程上执行。

您应该使用 DispatcherTimer 而不是 Threading.Timer class。