The calling thread cannot access the object because different thread owns it

mriz81
mriz81 used Ask the Experts™
on
Hi,

I am writing a WPF application that scans a folder and then shows latest image in it.
Its all fine when UpdateImage function is called on click of a button.
But If I call it from FileSystemWatcher's event it gives error on this line
 image1.Source = new BitmapImage(new Uri(F_final.FullName));
Error is
"The calling thread cannot access the object because different thread owns it"

Why is this?? How to fix it??

I need urgent reply.

Thanks



private void UpdateImage()
        {
            FileInfo[] Files = new DirectoryInfo(@FolderPath).GetFiles("*.*");
            FileInfo F_final = null;
            int counter = 0, cResult = 0;
 
            foreach (FileInfo F in Files)
            {
                if (F.Extension.ToLower() == ".jpg" || F.Extension.ToLower() == ".gif")
                {
                    if (counter == 0) F_final = F;
                    counter++;
                    if (counter > 1)
                    {
                        cResult = DateTime.Compare(F.LastWriteTime, F_final.LastWriteTime);
                        if (cResult == 1) F_final = F;
                    }
                }
            }
            if (F_final != null) {
                image1.Source = new BitmapImage(new Uri(F_final.FullName));                
            } else {
                image1.Source = null;
            }
        }

Open in new window

Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®

Commented:
Problem is that your thread running current function and Image1 object belong to another thread.

As per my thinking  Image1 is control so it might belong to another thread.

1. For window application use Invoke.

2. For WPF use dispatcher.

http://msdn.microsoft.com/en-us/magazine/cc163328.aspx

Author

Commented:
Its WPF application.

I have already seen the link you sent in last message but not sure how to use it.

Can you please modify my code to use the Dispatcher ??
Announcing the Winners!

The results are in for the 15th Annual Expert Awards! Congratulations to the winners, and thank you to everyone who participated in the nominations. We are so grateful for the valuable contributions experts make on a daily basis. Click to read more about this year’s recipients!

Why is this ?

The filesystem watcher watches changes on the file system, to keep your application unaffected by its monitoring, it does so in a separate thread. As a downside, all events coming from the watcher will be owned by the watcher's thread. Meaning that you cannot change objects that are owned by the main thread.

How to fix it.

You can fix this, by telling the main thread ( that owns the image1 object) to execute an action. You can do so by passing it a delegate through the Invoke method. Attached code snippet should make things clear.
public void EventMethod()
        {
            // this is the method called by the watcher.
            var fileName = @"c:\temp\test.jpg";
 
            // use the invoke method to update your image.
            this.Invoke(new InvokeUpdateImageDelegate(UpdateImage), fileName);
        }
 
        // the delegate definition.
        private delegate void InvokeUpdateImageDelegate(string fileName);
 
        // the function that updates the image.
        public void UpdateImage(string fileName)
        {
            image.Image = Image.FromFile(fileName);
        }

Open in new window

Commented:

delegate void setImage(string path);
 
private void UpdateImage()
        {
            FileInfo[] Files = new DirectoryInfo(@FolderPath).GetFiles("*.*");
            FileInfo F_final = null;
            int counter = 0, cResult = 0;
 
            foreach (FileInfo F in Files)
            {
                if (F.Extension.ToLower() == ".jpg" || F.Extension.ToLower() == ".gif")
                {
                    if (counter == 0) F_final = F;
                    counter++;
                    if (counter > 1)
                    {
                        cResult = DateTime.Compare(F.LastWriteTime, F_final.LastWriteTime);
                        if (cResult == 1) F_final = F;
                    }
                }
            }
            if (F_final != null) 
            {
	            this.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, (setImage)delegate(string img)
        	    	{
                	BitmapImage img11 = new BitmapImage(new Uri(img));
	                image1.Source = img11; 
        		},F_final.FullName);
                
            } else {
	                this.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, (setImage)delegate(string img)
        	    	{                	
	                image1.Source = null; 
        		},"");
 
            }
        }

Open in new window

Commented:
Hello mriz81,

did you tried my last solution ? it must work.

Author

Commented:
Thanks for solution

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial