The calling thread cannot access this object because a different thread owns it

43,923

Solution 1

You can look through this classes in reflector. Exception will rise in cb.Freeze(). In

CroppedBitmap cb = new CroppedBitmap(bf, new Int32Rect(1,1,5,5));

case constructor did something like this:

this.this.Source = source;

So source wasn't created in current thread, and so exception will rise. In

new WriteableBitmap(bf)

case, constructor synchronize with bf object and new source is created in current thread, so, no exceptions will rise. If you are interested in In Depth details, you can always reflect base libraries with Reflector :)

Solution 2

Following code might help you solve the issue of updating a gui element from another thread :

Module level

delegate void updateCallback(string tekst);

This is the method to update your element :

private void UpdateElement(string tekst)
{
    if (element.Dispatcher.CheckAccess() == false)
    {
        updateCallback uCallBack = new updateCallback(UpdateElement);
        this.Dispatcher.Invoke(uCallBack, tekst);
    }
    else
    { 
//update your element here
    }
 }

Solution 3

When working with WPF be aware that if you create a UI object in one thread you can't access it from another thread. Your UI objects should (typically) be created the UI thread, and then you need the UI thread to access them later. No other thread will be able to access objects created on the UI thread.

If you need to access a UI object from another thread you need the UI thread Dispatcher, and then you can use this to invoke calls on the UI thread.

I've spent many hours in frustration of similar problems to this - believe me.. Check out this question - it gave me a lot of useful information on the subject.

Solution 4

I had the same issue and fixed the problem by creating my UIElement in the UI thread by using its dispatcher (that can be accessed by Application.Current.Dispatcher ).

Before:

public static UIElement CreateUIElement()
{
    UIElement element = new UIElement();
    //Initialized the UIElement here
    return element;
}

This code caused an XamlParseException as it was called in a different thread than the UI thread.

My working solution :

public static UIElement CreateUIElement()
{
    UIElement element = null;
    Application.Current.Dispatcher.Invoke(
       System.Windows.Threading.DispatcherPriority.Normal, new Action(
          delegate()
          {
              element = new UIElement();
              // Initialize your UIElement here
          }));
    return element;
}

More info about the dispatcher can be found here http://tech.pro/tutorial/800/working-with-the-wpf-dispatcher

Good luck

Share:
43,923
zunyite
Author by

zunyite

Updated on October 09, 2020

Comments

  • zunyite
    zunyite over 3 years

    Why I can't create CroppedBitmap in the following code? I got an exception:

    The calling thread cannot access this object because a different thread owns it.

    If I change the code to

    CroppedBitmap cb = new CroppedBitmap(new WriteableBitmap(bf), new Int32Rect(1, 1, 5, 5));
    

    the exception is gone? why ?

    Code 1, an exception at cb.Freeze():

    public MainWindow()
    {
        InitializeComponent();
    
        ThreadPool.QueueUserWorkItem((o) =>
            {
                //load a large image file
                var bf = BitmapFrame.Create(
                    new Uri("D:\\1172735642.jpg"),
                    BitmapCreateOptions.None,
                    BitmapCacheOption.None);
                bf.Freeze();
                Dispatcher.BeginInvoke(
                    new Action(() =>
                        {
                            CroppedBitmap cb = new CroppedBitmap(bf, new Int32Rect(1,1,5,5));
                            cb.Freeze();
                            //set Image's source to cb....
                        }), 
                        DispatcherPriority.ApplicationIdle);
             }
        );
    }
    

    Code 2, works:

        ThreadPool.QueueUserWorkItem((o) =>
        {
            var bf = BitmapFrame.Create(
                    new Uri("D:\\1172740755.jpg"),
                    BitmapCreateOptions.None,
                    //BitmapCreateOptions.DelayCreation,
                    BitmapCacheOption.None);
            bf.Freeze();
            var wb = new WriteableBitmap(bf);
            wb.Freeze();
            this.Dispatcher.Invoke(
                new Action(() =>
                {
                    var r = new Int32Rect(1, 1, 5, 5);
                    CroppedBitmap cb = new CroppedBitmap(wb, r);
                    cb.Freeze();
                    //set Image's source to cb....
                    Image.Source = cb;
                }),
                DispatcherPriority.ApplicationIdle);
        }
    );
    

    Code 3, works without WritableBitmap:

    ThreadPool.QueueUserWorkItem((o) =>
        {
            var bf = BitmapFrame.Create(
                    new Uri("D:\\1172735642.jpg"),
                    BitmapCreateOptions.None,
                    //BitmapCreateOptions.DelayCreation,
                    BitmapCacheOption.None);
            bf.Freeze();
            var bf2 = BitmapFrame.Create(bf);
            bf2.Freeze();
    
            this.Dispatcher.Invoke(
                new Action(() =>
                {
                    var r = new Int32Rect(1, 1, 5, 5);
                    BitmapSource cb = new CroppedBitmap(bf2, r);
                    cb.Freeze();
                    //set Image's source to cb....
                    Image.Source = cb;
                }),
                DispatcherPriority.ApplicationIdle);
        }
    );
    
  • zunyite
    zunyite about 14 years
    But, after I change the code to CroppedBitmap cb = new CroppedBitmap(new WriteableBitmap(bf), new Int32Rect(1, 1, 5, 5)); no exception. why? they are still in different thread.
  • stiank81
    stiank81 about 14 years
    Sorry - I'm not sure about that. Haven't used WriteableBitmap. Maybe the documentation can give you a hint? msdn.microsoft.com/en-us/library/…
  • zunyite
    zunyite about 14 years
    I'v updated mycode, please see my new code 2, CroppedBitmap cb = new CroppedBitmap(wb, r); wb now in different thread, but NO exception. why ?
  • Andrew
    Andrew about 14 years
    No exceptions was thrown because WriteableBitmap was created to work with multiple threads (it even has lock and unlock methods) msdn.microsoft.com/en-en/library/… And CroppedBitmap - isn't, actually at first, i thought that only BitmapFrame doens't like call from multiple threads, i was wrong, CroppedBitmap doesn't like it to :)
  • zunyite
    zunyite about 14 years
    I'v updated mycode again, please see my new code 3, now the I replace WritableBitmap with BitmapFrame, It still works.
  • Andrew
    Andrew about 14 years
    BitmapFrame at first seems the same but actually different constructors created different classes (BitmapFrame is abstract actually), bf is BitmapFrameDecode, and bf2 is BitmapFrameEncode, they are internal classes derived from BitmapFrame, so one is support access from other thread when the other isn't. Actually some properties have complex getter that throw exception, so if you are interested in it, go go go Disassemble :)
  • zunyite
    zunyite about 14 years
    Thanks, I'd try to trace the code with reflector, but I have no idea how to tell if a bitmap class support thread or not.
  • Andrew
    Andrew about 14 years
    For this i think debugger is much better then reflector :) Reflector helps you to understand what happend and why, but with debugger you can just look through properties and find out is they are good or throw exception, but you have to create code example though :)
  • NoWar
    NoWar over 12 years
    I used it and get the error: {"Cannot use a DependencyObject that belongs to a different thread than its parent Freezable."}
  • MrWuf
    MrWuf over 11 years
    Great implementation. Easy to use.