为什么我不能在 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。
我在 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。