在 WPF 中使用非 UI 线程从内存流设置图像控件的源
Setting source of an Image control from Memory Stream using Non-UI thread in WPF
我正在从指纹扫描仪捕获图像,我想在图像控件中实时显示捕获的图像。
//Onclick of a Button
Thread WorkerThread = new Thread(new ThreadStart(CaptureThread));
WorkerThread.Start();
所以我如上所述创建了一个线程,并调用了从设备捕获图像的方法,并如下设置图像控件的源。
private void CaptureThread()
{
m_bScanning = true;
while (!m_bCancelOperation)
{
GetFrame();
if (m_Frame != null)
{
MyBitmapFile myFile = new MyBitmapFile(m_hDevice.ImageSize.Width, m_hDevice.ImageSize.Height, m_Frame);
MemoryStream BmpStream = new MemoryStream(myFile.BitmatFileData);
var imageSource = new BitmapImage();
imageSource.BeginInit();
imageSource.StreamSource = BmpStream;
imageSource.EndInit();
if (imgLivePic.Dispatcher.CheckAccess())
{
imgLivePic.Source = imageSource;
}
else
{
Action act = () => { imgLivePic.Source = imageSource; };
imgLivePic.Dispatcher.BeginInvoke(act);
}
}
Thread.Sleep(10);
}
m_bScanning = false;
}
现在,当我 运行 项目时,它在行 Action act = () => { imgLivePic.Source = imageSource; };
上抛出异常,提示“调用线程无法访问此对象,因为另一个线程拥有它”。
我做了一些研究,发现如果我想在非 UI 线程上使用 UI 控件,我应该使用 Dispatcher.Invoke 方法,如你所见,我有,但我是仍然得到同样的例外。
有人可以告诉我我做错了什么吗?
BitmapImage
本身需要在Dispatcher
线程上构建。
BitmapImage不一定要在UI线程中创建。如果您 Freeze
它,稍后可以从 UI 线程访问它。因此,您还将减少应用程序的资源消耗。一般来说,如果可能,您应该尝试冻结所有 Freezable,尤其是位图。
using (var bmpStream = new MemoryStream(myFile.BitmatFileData))
{
imageSource.BeginInit();
imageSource.StreamSource = bmpStream;
imageSource.CacheOption = BitmapCacheOption.OnLoad;
imageSource.EndInit();
}
imageSource.Freeze(); // here
if (imgLivePic.Dispatcher.CheckAccess())
{
imgLivePic.Source = imageSource;
}
else
{
Action act = () => { imgLivePic.Source = imageSource; };
imgLivePic.Dispatcher.BeginInvoke(act);
}
我正在从指纹扫描仪捕获图像,我想在图像控件中实时显示捕获的图像。
//Onclick of a Button
Thread WorkerThread = new Thread(new ThreadStart(CaptureThread));
WorkerThread.Start();
所以我如上所述创建了一个线程,并调用了从设备捕获图像的方法,并如下设置图像控件的源。
private void CaptureThread()
{
m_bScanning = true;
while (!m_bCancelOperation)
{
GetFrame();
if (m_Frame != null)
{
MyBitmapFile myFile = new MyBitmapFile(m_hDevice.ImageSize.Width, m_hDevice.ImageSize.Height, m_Frame);
MemoryStream BmpStream = new MemoryStream(myFile.BitmatFileData);
var imageSource = new BitmapImage();
imageSource.BeginInit();
imageSource.StreamSource = BmpStream;
imageSource.EndInit();
if (imgLivePic.Dispatcher.CheckAccess())
{
imgLivePic.Source = imageSource;
}
else
{
Action act = () => { imgLivePic.Source = imageSource; };
imgLivePic.Dispatcher.BeginInvoke(act);
}
}
Thread.Sleep(10);
}
m_bScanning = false;
}
现在,当我 运行 项目时,它在行 Action act = () => { imgLivePic.Source = imageSource; };
上抛出异常,提示“调用线程无法访问此对象,因为另一个线程拥有它”。
我做了一些研究,发现如果我想在非 UI 线程上使用 UI 控件,我应该使用 Dispatcher.Invoke 方法,如你所见,我有,但我是仍然得到同样的例外。
有人可以告诉我我做错了什么吗?
BitmapImage
本身需要在Dispatcher
线程上构建。
BitmapImage不一定要在UI线程中创建。如果您 Freeze
它,稍后可以从 UI 线程访问它。因此,您还将减少应用程序的资源消耗。一般来说,如果可能,您应该尝试冻结所有 Freezable,尤其是位图。
using (var bmpStream = new MemoryStream(myFile.BitmatFileData))
{
imageSource.BeginInit();
imageSource.StreamSource = bmpStream;
imageSource.CacheOption = BitmapCacheOption.OnLoad;
imageSource.EndInit();
}
imageSource.Freeze(); // here
if (imgLivePic.Dispatcher.CheckAccess())
{
imgLivePic.Source = imageSource;
}
else
{
Action act = () => { imgLivePic.Source = imageSource; };
imgLivePic.Dispatcher.BeginInvoke(act);
}