tags:

views:

152

answers:

1

Hi,

I have an BitmapFrame object created by a working thread (not UI thread) and placed in a static collection.

then, I have a different working thread assigning this object to an Image object owned by the UI thread.

As you can imagine, I can't access the Image object (As it belongs to the UI thread) and I get: "calling thread cannot access the object because different thread owns it"

So, I tried solving it by doing the following:

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

II is the Image item (created by a working thread and available through a static class) and imageMainImage is the Image object owned by the UI thread.

But now, again, I get the "calling thread..." but this time I get it because the II object belongs to a different thread (the first working thread).

What I'm trying to do is have one thread work with 2 image elements that belong to different threads.

I'm trying to work the whole process differently but was wondering, is there a solution to this?

thanks.

A: 

You need to do a CheckAccess() call on the Dispatcher first to see if you are on the UI thread and therefore capable of updating the UI item.

Here is a helper function i wrote to update my comboboxes in WPF, you can easily adapt it to suit an Image control, and it is a good example of the CheckAccess call:

    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);

So the function checks if it has access, if it does it assigns the datasource. If it doesn't, then it calls itself back but this time within the context of the UI thread.

There is probably a more succinct way to code the delegate creation, but that isn't so good for people trying to understand the sample, hence the explicit delegate definition.

slugster
My first response was "niicceee....." but after reading the lines one after the other my response turned to "Yaiks!!", twisted horror code that works.
Gilad
It looks nasty, but the whole self-calling function thing is the endorsed way to do it, all i did was beef up the process to suit my specific needs. Yours can be a lot simpler, especially if you make the delegate creation/declaration more concise.
slugster