Модификация объектов внутри WPF BackgroundWorker для длительной операции - PullRequest
0 голосов
/ 03 февраля 2011

У меня есть вопрос относительно фонового работника и отображения пользовательского интерфейса в приложении WPF во время выполнения 5-секундной операции.У меня есть объект, который должен подключиться к камере, и это подключение занимает некоторое время (несколько секунд).Между тем, когда этот объект пытается подключиться, я хочу отобразить отдельное окно с вращающимся кругом (WaitWindow), которое предполагает, что приложение все еще работает, но пользователь должен подождать несколько секунд, пока соединение не будет установлено.Все идет нормально.

Проблема в том, что у меня есть таймер, который каждую секунду получает текущее изображение с камеры в виде растрового изображения и отображает это растровое изображение в элементе управления изображения на холсте (_image).Таким образом, когда необходимо отобразить этот растровый файл, приложение аварийно завершает работу с этим исключением:

"Windows запустила точку останова в mywpfapp.exe. Это может быть связано с повреждением кучи, что указывает на ошибку в mywpfapp..exe или любой из загруженных им библиотек DLL. Это также может быть связано с тем, что пользователь нажимает клавишу F12, когда mywpfapp.exe находится в фокусе. В окне вывода может быть больше диагностической информации. "

Я думаю, это потому, чторазличных потоков - потока backgroundWorkers, который подключается к камере - потока пользовательского интерфейса, который хочет отобразить растровое изображение

Первая строка кода, в которой он генерирует исключение, - «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 Ответ

1 голос
/ 03 февраля 2011

Это может быть связано с привязкой к потоку, а также с тем фактом, что ваш таймер (в настоящее время) работает в потоке ThreadPool, а не в потоке пользовательского интерфейса.

Возможно, вы захотите переключиться на использование DispatcherTimer вместо.Это приведет к тому, что события таймера будут запускаться в потоке пользовательского интерфейса, а не в потоке ThreadPool, что позволит вам сохранить всю обработку изображений в основном потоке.

...