Многопоточность в WPF с использованием C # (с фоновым рабочим) - PullRequest
3 голосов
/ 05 октября 2010

Я написал код для сохранения изображения, сгенерированного приложением. Размер изображения составляет около 32-35 МБ. Сохранение изображения в файл BMB занимает много времени, около 3-5 секунд. Для этой цели я использовал фонового работника, но при запуске фонового работника выдается сообщение об ошибке типа «не удается получить доступ к объекту, так как он создан в другом потоке».

Следующий код:

 private void btnSaveDesign_Click(object sender, RoutedEventArgs e)
    {
        Microsoft.Win32.SaveFileDialog sfd = new Microsoft.Win32.SaveFileDialog();
        sfd.Title = "Save design as...";
        sfd.Filter = "BMP|*.bmp";
        if (sfd.ShowDialog() == true)
        {
            ww = new winWait();
            ww.Show();
            System.ComponentModel.BackgroundWorker bw = new System.ComponentModel.BackgroundWorker();
            bw.DoWork += new System.ComponentModel.DoWorkEventHandler(bw_DoWork);
            bw.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
            fName = sfd.FileName;
            cache = new CachedBitmap((BitmapSource)imgOut.Source, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);

            bw.RunWorkerAsync();


        }  
    }

    void bw_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
    {
        ww.Close();
    }

    void bw_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
    {
        BmpBitmapEncoder encoder = new BmpBitmapEncoder();
        encoder.Frames.Add(BitmapFrame.Create(cache)); //here... it says cant access...
        using (FileStream file = File.OpenWrite(fName))
        {
            encoder.Save(file);
        }
    }

Я объявил «кеш» глобальным объектом. (Подобный прием работал, когда я программировал в Windows Forms с VB.NET.)

ww - это окно ожидания, которое я хочу отобразить во время выполнения прецессии.

Как это сделать? Есть ли другой простой способ многопоточности в WPF?

Ответы [ 4 ]

4 голосов
/ 05 октября 2010

При создании объектов WPF они назначаются объекту Dispatcher.Это запрещает любые потоки, кроме потока создания, для доступа к объекту.Это можно обойти, заморозив объект, вызвав метод freeze.Вам необходимо вызвать Freeze для вашего объекта bitmapsource.Как только вы заморозили свой объект, он становится недоступным для редактирования

4 голосов
/ 05 октября 2010

Ваша проблема возникает из-за того, что вы обращаетесь к объекту, который не создан фоновым рабочим потоком. Обычно это происходит, если вы обращаетесь к элементу управления пользовательского интерфейса, который создан в главном потоке и доступен из другого потока.

Используйте код ниже.

Dispatcher.Invoke
(
    new Action(
        delegate()
        {
            BmpBitmapEncoder encoder = new BmpBitmapEncoder();
            encoder.Frames.Add(BitmapFrame.Create(cache));
            using (FileStream file = File.OpenWrite(fName))
            {
                encoder.Save(file);
            }
        }
    )
);
0 голосов
/ 11 ноября 2014

.NET Framework предоставляет простой способ начать работу с компонентом BackgroundWorker.Это оборачивает большую часть сложности и делает порождение фонового потока относительно безопасным.Кроме того, он позволяет обмениваться данными между фоновым потоком и потоком пользовательского интерфейса без какого-либо специального кодирования.Вы можете использовать этот компонент с приложениями WinForms и WPF.BackgroundWorker предлагает несколько функций, которые включают создание фонового потока, возможность отмены фонового процесса до его завершения и возможность сообщить о ходе выполнения обратно в пользовательский интерфейс.

0 голосов
/ 05 октября 2010

Я думаю, вы должны передать кеш как параметр в новый поток:

bw.RunWorkerAsync(cache);

и получить его из метода DoWork:

var cache=(CacheType) e.Argument;
...