开发者

Accessing 2 UI items from a 3rd thread in WPF

开发者 https://www.devze.com 2022-12-16 03:12 出处:网络
I have a BitmapFrame object created by a working thread (not UI thread) and placed in a static collection.

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

Then, I have a different wor开发者_运维问答king thread assigning this object to an Image object owned by the UI thread.

As you can imagine, I can't access theImage 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.


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号