I’m designing a media player, and I have a method called AddDirectory, which adds all the movies in a specified directory to the media player’s database. This method takes a while to process, and so I decided to make it run in the background so the user can keep using the program.
Here is the AddDirectory method:
/// <summary>
/// Adds all the movies in the specified directory and all its subdirectories to the database.
/// </summary>
/// <param name="path">A string representing the directory path.</param>
/// <returns>True if all the files were added successfully, false otherwise.</returns>
/// <exception cref="System.ArgumentException">Thrown if the path does not lead to a directory.</exception>
public static bool AddDirectory(string path)
{
if (!FileProcessing.IsDirectory(path))
{
return false;
}
List<string> filePaths = FileProcessing.GetDirectoryMovieFiles(path); //a list containing the paths of all the movie files in the directory
//add the movie in a separate thread so as to not interrupt the flow of the program
Thread thread = new Thread(() =>
{
foreach (string filePath in filePaths)
{
AddMovie(filePath);
}
});
//make the thread STA and start it
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
return true;
}
In the same class, I have the following event and delegate:
public delegate void MovieAddedHandler(MovieEventArgs e);
/// <summary>
/// Called on when a movie is inserted into the database.
/// </summary>
public static event MovieAddedHandler MovieAdded;
I need this event so that the GUI knows when a new movie has been added to the database, and so it can update the GUI and notify the user accordingly. So when I add a directory with, say, 50 movies, the event is called on 50 times.
Now the GUI updating is where I’m having difficulty.
I have the following code segment, which is part of a method that is called on whenever the user clicks on the “Add Directory” label in the GUI.
MovieInsertion.MovieAdded += (e2) =>
{
this.movies = MovieDataRetrieval.GetMovies();
this.labels.Clear();
this.InitializeMovieLabels();
};
The GetMovies() method returns a List of all the Movies in the database (Represented by a separate Movie class). I then clear all the labels in the GUI grid, then initialize them again, so that each time a movie is added, the user can access the movie immediately in the program, without having to wait for the rest of the movies in the directory to be added.
The error itself is called in the InitializeMovieLabels() method:
foreach (Label labelIterator in labels)
{
this.grid.Children.Add(labelIterator);
}
The “labels” variable is a List of all the Labels that represent the movies in the database. I want to add each label to the grid.
The error I get is (as described in the title): “The calling thread cannot access this object because a different thread owns it.”
I’m sort of (very) inexperienced with threads, and I tried searching for a solution but was unsuccessful. Sorry if I went a little overboard with the details :).
Any help would be appreciated.
Use
MethodInvokerwhere you updating GUI from different thread.Your labels.clear() statement try to update GUI from different thread. So use this type of code.
Where you want to update GUI from different thread make sure to use
MethodInvokerdelegate.