Доступ к 2 элементам пользовательского интерфейса из 3-го потока в WPF - PullRequest
1 голос
/ 07 января 2010

У меня есть BitmapFrame объект, созданный рабочим потоком (не потоком пользовательского интерфейса) и помещенный в статическую коллекцию.

Затем у меня есть другой рабочий поток, назначающий этот объект Image объекту, принадлежащему потоку пользовательского интерфейса.

Как вы можете себе представить, я не могу получить доступ к объекту Image (поскольку он принадлежит потоку пользовательского интерфейса), и я получаю: "calling thread cannot access the object because different thread owns it".

Итак, я попытался решить ее, выполнив следующее:

imageMainImage.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, new Action<ImageItem>(delegate(ImageItem A) {
    imageMainImage.Source = A.ManipulatedPreview;                
}), II);

II - это элемент Image (созданный рабочим потоком и доступный через статический класс), а imageMainImage - это объект Image, принадлежащий потоку пользовательского интерфейса.

Но теперь я снова получаю "calling thread...", но на этот раз я получаю его, потому что объект II принадлежит другому потоку (первому рабочему потоку).

Я пытаюсь сделать так, чтобы один поток работал с 2 Image элементами, которые принадлежат разным потокам.

Я пытаюсь поработать весь процесс по-другому, но мне было интересно, есть ли решение для этого?

спасибо.

1 Ответ

0 голосов
/ 07 января 2010

Сначала необходимо выполнить вызов CheckAccess () для Dispatcher, чтобы выяснить, находитесь ли вы в потоке пользовательского интерфейса и, следовательно, способны обновлять элемент пользовательского интерфейса.

Вот вспомогательная функция, которую я написал для обновления моих комбинированных списков в WPF, вы можете легко адаптировать ее для соответствия элементу управления Image, и это хороший пример вызова CheckAccess:

    private void UpdateComboDataSource<T>(ComboBox ctrl, IEnumerable<T> datasource, string displayPath, string valuePath)
    {
        if (ctrl == null)
            throw new ArgumentNullException("Control to be bound must not be null");

        //check if we are on the control's UI thread:
        if (ctrl.Dispatcher.CheckAccess())
        {
            //we have full access to the control, no threading issues, so let's rip it up and databind it
            datasource = datasource.OrderBy(x => x);
            if (displayPath != null && ctrl.DisplayMemberPath == null)
                ctrl.DisplayMemberPath = displayPath;
            if (valuePath != null && ctrl.SelectedValuePath == null)
                ctrl.SelectedValuePath = valuePath;

            ctrl.ItemsSource = datasource;
        }
        else
        {
            //we don't have full access to the control because we are running on a different thread, so 
            //we need to marshal a call to this function from the control's UI thread
            UpdateComboDataSourceDelegate<T> del = new UpdateComboDataSourceDelegate<T>(this.UpdateComboDataSource);
            ctrl.Dispatcher.BeginInvoke(del, ctrl, datasource, displayPath, valuePath);
        }
    }


private delegate void UpdateComboDataSourceDelegate<T>(ComboBox ctrl, IEnumerable<T> dataSource, string displayPath, string valuePath);

Таким образом, функция проверяет, имеет ли она доступ, назначает ли она источник данных. Если это не так, то он перезванивает сам, но на этот раз в контексте потока пользовательского интерфейса.

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

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