修改WPF BackgroundWorker中的对象以进行耗时的操作

时间:2011-02-03 17:22:02

标签: wpf user-interface backgroundworker

我对后台工作程序有疑问,并且在5秒操作正在进行时在WPF应用程序中显示UI。我有一个必须连接到相机的对象,这个连接需要一段时间(几秒钟)。同时,当这个对象试图连接时,我想显示一个带旋转圆圈的单独窗口(WaitWindow),表明应用程序仍在运行,但用户必须等待几秒钟才能完成连接。到现在为止还挺好。

问题在于我有一个计时器,它每秒从摄像机获取当前图像作为位图,并在画布上的Image控件中显示该位图(_image)。因此,当必须呈现此位图时,应用程序会因此异常而崩溃:

“Windows在mywpfapp.exe中触发了断点 这可能是由于堆的损坏,这表示mywpfapp.exe或它已加载的任何DLL中的错误。 这也可能是由于用户在mywpfapp.exe具有焦点时按下F12。 输出窗口可能包含更多诊断信息。“

我认为这是因为线程不同 - backgroundWorkers连接到相机的线程 - 想要显示位图的UI线程

它抛出异常的第一行代码是“source.Save(ms,System.Drawing.Imaging.ImageFormat.Bmp);”,即使源代码似乎有效。

以下是代码:

public partial class MainWindow
{
    private WaitWindow _waitWindow;
    private ConnectionObject _myConnObject;
    private Timer _myTimer;
    private bool _isConnected;

    public MainWindow()
    {
        _myTimer = new Timer();
        _myTimer.Tick += new EventHandler(TimerEventProcessor);     
    }

    private void btnConnect_Click(object sender, RoutedEventArgs e)
    {
        _isConnected = false;

        BackgroundWorker backgroundWorker = new BackgroundWorker();
        backgroundWorker.DoWork += (sender1, e1) =>
        {
            // this takes at least 5 seconds
            _isConnected = _myConnObject.Connect();
        };
        backgroundWorker.RunWorkerCompleted += (sender1, e1) =>
        {
            ConnectEnded();
        };
        backgroundWorker.RunWorkerAsync();

        // show wait window
        _waitWindow = new WaitWindow();
        _waitWindow.Owner = this;
        _waitWindow.ShowDialog();
    }

    private void ConnectEnded()
    {
        if (_waitWindow != null)
        {
            _waitWindow.Close();
            _waitWindow = null;
        }

        if (_isConnected)
        {
            lblStatus.Content = "connected";
        }
        else
        {
            lblStatus.Content = "not connected";
        }
    }

    private BitmapSource TimerEventProcessor(Object myObject, EventArgs myEventArgs)
    {
        if (_isConnected)
        {
            // the bitmap is 
            Bitmap source = _myConnObject.GetBitmapFromDevice();
            if (source == null)
            {
                _image.Source = null;
            }
            else
            {
                MemoryStream ms = new MemoryStream();
                // here it throws an exception
                source.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
                ms.Position = 0;
                BitmapImage bi = new BitmapImage();
                bi.BeginInit();
                bi.StreamSource = ms;
                bi.EndInit();
                _image.Source = bi;
            }
        }
    }
}

您对此代码有什么问题有什么想法吗?或者有更好的方法吗?

非常感谢!

1 个答案:

答案 0 :(得分:1)

这可能是由于具有线程亲和性,以及您的Timer(当前)在ThreadPool线程上运行,而不是在UI线程上运行。

您可能需要考虑切换为使用DispatcherTimer。这将导致计时器的事件在UI线程而不是ThreadPool线程上触发,这将允许您将所有图像处理保留在主线程上。