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