2

After I tried lots and lots of solutions I couldn't solve this problem by any means so I started to believe that there is no solution for this problem.

I have an object that contains complex attributes. E.g: List<SomeComplexObject>. I am running a method from this class on a worker thread to keep the GUI running until the worker thread finishes. When it finishes execution, I want to use the attributes of these objects to update GUI let's say I want to use List<SomeComplexObject> looping through this list and update the GUI. But each time I try to access this list the debugger throws an InvalidOperationException: The calling thread cannot access this object because a different thread owns it.

I tried to make all attributes of this class volatile but with no hope I also used Lazy<T> class approach to solve but the same problem occurs.

Class that contain the worker function:

public class MainModules
{

    #region Attributes

    public VIDEO video; 

    public string VideoPath
    {
        get;
        set;
    }

    LowLevelModule lowLevelOutput;

    //this list that I want to use to Update GUI 
    public volatile List<FaceRecognitionModule> faceModuleOutput;

    //worker function running on different thread
     public void RunMainModules()
     {
        //some complex work to set the class attributes
     }
 }

Thread creation in GUI class

 private void RunMainModules_BtnClick(object sender, RoutedEventArgs e)
    {
      //  MainModule = new MainModules(mainModuleObj, Inpath, lif, keyframefolderpath, trdbpath, labelspath, rrankspath, alignmatpath, 11, 10);
        this.LazyMainModule = new Lazy<MainModules>(this.InitLazyMainModule);
        MainModuleThread = new Thread(this.RunMainModules);
        MainModuleThread.Start(MainModule);

    }

    public MainModules InitLazyMainModule()
    {
        return new MainModules(mainModuleObj, Inpath, lif, keyframefolderpath, trdbpath, labelspath, rrankspath, alignmatpath, 11, 10);
    }
     public void RunMainModules(Object obj)
    {
        //MainModules mm = obj as MainModules;
        MainModules mm = LazyMainModule.Value;
        mm.RunMainModules();
        this.Dispatcher.Invoke((Action)(() =>
        {
            this.InitSpeechRec_Btn.IsEnabled = true;
        }));
    }

When I try to access faceModuleOutput in class MainModules from GUI I got InvalidOperationException.

Image img = new Image();
//InvalidOperationException occurs here
img.Source = LazyMainModule.Value.faceModuleOutput[0].keyframes[1].keyframe;

To brief this post: I want to access an object instantiated by a background thread from main thread but it throws

InvalidOperationException : The calling thread cannot access this object because a different thread owns it. 
Kristof U.
  • 1,263
  • 10
  • 17
Ibrahim Amer
  • 1,147
  • 4
  • 19
  • 46

3 Answers3

0

A UI control needs to be created/modified from the GUI Thread. Doing otherwise is illegal.

It seems that the MainModuleThread is (at least) creating and modifying an Image . This should be done in the GUI Thread (the one that called RunMainModules_BtnClick)

quantdev
  • 23,517
  • 5
  • 55
  • 88
  • Sir, this is what I actually do all GUI updating code runs from main thread but it uses an object created by another thread to perform the update – Ibrahim Amer Jun 01 '14 at 00:43
  • Yes, this is illegal. Do it th other way : the GUI Thread performs itself the update. – quantdev Jun 01 '14 at 00:46
  • How do I suppose to do that ? since the data used to update GUI results from a background worker – Ibrahim Amer Jun 01 '14 at 00:48
  • this post will answer your last question : http://stackoverflow.com/questions/661561/how-to-update-the-gui-from-another-thread-in-c – quantdev Jun 01 '14 at 00:52
  • Sir, this post explains how to update a UI element from another thread which isn't I want to do. Now I am on MainThread and I want to update a UI element using an object created by another thread – Ibrahim Amer Jun 01 '14 at 00:57
0

You cannot modify or even access pretty much anything that relates to the UI thread from another thread. This can get pretty extreme/annoying sometimes because you can't even get the value in a textbox or check if a checkbox is checked or not. If you want to perform an action on an object owned by the UI thread you need to invoke the UI thread to do it.

UIObject.Dispatcher.Invoke(() => {
   //[Perform your action in here]
  });
cost
  • 4,420
  • 8
  • 48
  • 80
0

Finally I found the solution ... Class BitmapImage is thread-affine so it can't be accessed by multiple threads you need first to make it opened for reading only closed for writing so the compiler can guarantee that no threads will modify it's content

So the solution ... :

 //keyframe here is a BitmapImage so on creation we must call keyframe.Freeze()
 LazyMainModule.Value.faceModuleOutput[0].keyframes[1].keyframe;

class KeyFrame:

public class KeyFrame
{
    public volatile BitmapImage keyframe;
    public volatile List<string> personsNames;
    public volatile List<string> categories;

    public KeyFrame(BitmapImage keyframe, List<string> personsNames, List<string> categories)
    {
        this.keyframe = keyframe;
        //here we call Freeze funcition on creation to make it modifiable 
        this.keyframe.Freeze();
        this.personsNames = personsNames;
        this.categories = categories;
    }
}
Ibrahim Amer
  • 1,147
  • 4
  • 19
  • 46