Вызывающий поток не может получить доступ к этому объекту (переписан, но та же ошибка) - PullRequest
0 голосов
/ 14 декабря 2011

У меня есть окно MainFrame с элементом управления imageViewer. Также есть моя dll, которая вычисляет изменения для изображения, все работало нормально, прежде чем я решил добавить ProgressDialog. ((Идея была - сначала я загружаю изображение через dll в основной кадр (это все еще в порядке). Затем, если пользователь нажимает кнопку затем покажите ProgressDialog и в worker.DoWork создайте новый образ через тот же класс dllwrapper (я использую «new») Кажется, все в порядке, но когда я пытаюсь установить свойство currentImage элемента управления imageviewer (это не более, чем setter для Image), оно показывает мне эту ошибку! Это код моего userButtonClickHandler, с которого я запускаю ProgressDialog:

void OnThumbnailClick(object sender, RoutedEventArgs e)
{
    pd = new ProgressDlg();
    pd.Cancel += CancelProcess;

    int max = 1000;
    System.Windows.Threading.Dispatcher pdDispatcher = pd.Dispatcher;
    worker = new BackgroundWorker();
    worker.WorkerSupportsCancellation = true;
    LibWrap lwrap = new LibWrap();//!NEW instance for dll wrapper!

    worker.DoWork += delegate(object s, DoWorkEventArgs args)
    {
        imageViewer.CurrentImage = lwrap.engine2(BitmapFrame.Create(MyPrj.App.draggedImage));//ERROR IS HERE!!!//The calling thread cannot access this object because a different thread owns it.
        //what process?? 
    };

    worker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs args)
    {
        pd.Close();
    };

    worker.RunWorkerAsync();
    pd.ShowDialog();
}

Есть функция из того же класса MainFrame для отмены (Там тоже ОК)

void CancelProcess(object sender, EventArgs e)
{
   worker.CancelAsync();
 }

Это класс для ProgressDlg (в нем нет ничего, кроме индикатора выполнения и кнопки отмены):

public partial class ProgressDlg : Window
    {
        public ProgressDlg()
        {
            InitializeComponent();
        }
        public string ProgressText
        {
            set
            {
                this.lblProgress.Content = value;
            }
        }
        public int ProgressValue
        {
            set
            {
                this.progress.Value = value;
            }
        }
        public event EventHandler Cancel = delegate { };
        private void btnCancel_Click(object sender, RoutedEventArgs e)
        {
            Cancel(sender, e);
        }
    }
}

Я работаю над этой проблемой (почти) два дня и все еще не могу найти решение. Помогите мне, пожалуйста, если у вас есть идея.

1 ОБНОВЛЕНИЕ Мне кажется, что вы были правы в отношении этих потоков - когда я пытаюсь загрузить ранее загруженное (исходное) изображение (из основного потока) - он загружается нормально, но если я пытаюсь загрузить libWrap, это не удается из-за конфликта процессов!

worker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs args)
            {
imageViewer.Width = 1000;//work!
  imageViewer.CurrentImage = MyPrj.App.draggedImage;//Work!
imageViewer.CurrentImage = lwrap.engine2(BitmapFrame.Create(MyPrj.App.draggedImage));//Fail =(!

}

2 ОБНОВЛЕНИЕ Я пробовал эту конструкцию OnThumbnailClick

Application.Current.MainWindow.Dispatcher.BeginInvoke(new Action(() =>
                {
imaeViewer.CurrentImage = lwrap.engine2(BitmapFrame.Create(FXPhotoStudio.App.draggedImage));
}

Это вызвало ту же ошибку / Возможно, будет правильно передать это значение в MainThread (UI)? Но я понятия не имею, как. (Я не мог использовать сериализаторы - потому что это быстро вызывает операцию, и эти образы являются временными /

Ответы [ 3 ]

2 голосов
/ 14 декабря 2011

WPF не может изменять элементы, созданные в другом потоке.

Поэтому, если вы создаете ImageViewer в одном потоке, вы не можете изменять его свойства в другом потоке.

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

Или используйте Ответ Хенка , чтобы выполнить свою работу в другом потоке, но вернуть результат в основной поток, чтобы он мог обновить свойства вашего ImageViewer

2 голосов
/ 14 декабря 2011

Вам нужны как минимум эти изменения:

worker.DoWork += delegate(object s, DoWorkEventArgs args)
{
   args.Result = lwrap.engine2(BitmapFrame.Create(MyPrj.App.draggedImage));
};

worker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs args)
{
  if (args.Error != null)
  { ... }  // handle error
  else if (args.Cancelled)
  { ... } // handle Cancel
  else
  {
    imageViewer.CurrentImage = args.Result;
  }
  pd.Close();
}

Я не уверен, достаточно ли этого, но попробуйте еще раз.

0 голосов
/ 14 декабря 2011

imageViewer был создан в главном потоке приложения (что подходит, потому что это элемент управления пользовательского интерфейса). Элементы управления пользовательского интерфейса могут быть доступны ТОЛЬКО для потока, который его создал, и этот поток должен иметь своего собственного диспетчера (под которым я подразумеваю цикл обработки сообщений).

Удалите код потоков, и он будет работать.

Если вы хотите, чтобы это появилось во всплывающем окне и затем отобразило изображение после завершения преобразования, вам придется сохранять возвращаемое изображение в переменной до тех пор, пока вы не вернетесь к основному потоку, а затем выполнить назначение для imageViewer.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...