I have an app that I want to run the updating of each datagridview in the background on load concurrently instead of running sequentially on load. The code that gets loaded on app load is.

//##############################Movies

                   //update the list of filepaths
                   movieFilePaths_ = manageFilePathsFile.ReadFilePathsTextFile("Movie", filename);
                   //populate the list box
                   manageFilePathsFile.PopulateListBoxWithFilePaths(listBoxMoviePaths, movieFilePaths_);
                   if (movieFilePaths_.Count > 0)
                   {
                       movieList_ = onAppInitialLoad.GetMovieFilesFromActivePaths(movieFilePaths_, movieList_);
                   }

                   movieList_ = movieList_.OrderBy(x => x.FileName).ToList();
                   dataGridView1.DataSource = movieList_;

                   //##############################MusicVidoes

                   //update the list of filepaths
                   musicVideoFilePaths_ = manageFilePathsFile.ReadFilePathsTextFile("MusicVideo", filename);
                   //populate the list box
                   manageFilePathsFile.PopulateListBoxWithFilePaths(listBoxMusicVideoPaths, musicVideoFilePaths_);
                   if (musicVideoFilePaths_.Count > 0)
                   {
                       musicVideoList_ = onAppInitialLoad.GetMusicVideoFilesFromActivePaths(musicVideoFilePaths_, musicVideoList_);
                   }
                   musicVideoList_ = musicVideoList_.OrderBy(x => x.BandName).ThenBy(x => x.FileName).ToList();

                   dataGridViewMusicVideo.DataSource = musicVideoList_;


                   //##############################Rugby

                   ////update the list of filepaths
                   rugbyGameFilePaths_ = manageFilePathsFile.ReadFilePathsTextFile("Rugby", filename);
                   //populate the list box
                   manageFilePathsFile.PopulateListBoxWithFilePaths(listBoxRugbyFilePaths, rugbyGameFilePaths_);
                   if (rugbyGameFilePaths_.Count > 0)
                   {
                       rugbyGameList_ = onAppInitialLoad.GetRugbyGamesFilesFromActicePaths(rugbyGameFilePaths_, rugbyGameList_);
                   }

                   dataGridViewRugby.DataSource = rugbyGameList_;

                   interfaceOutputs.PopulateInterfaceOutputs(dataGridViewRugby, labelDataGridRugby);

Essentially each block beginning with //######################{name} would be run currently with the block above. I have implemented the backgroundworker on button presses to add and remove paths and running a single instance is easy.

I am stumped though on the best way to implement mutliple threads with out duplicating the current way I have of doing it, which is the code in full each time.

This is what I do to update a path and get the files from the background while the UI is still functioning.

Should I look at implementing backgroundworker as a class or method and calling that with parameters which would be each block of code? although I don't quite get that.

                BackgroundWorker bw = new BackgroundWorker();

                // this allows our worker to report progress during work
                bw.WorkerReportsProgress = true;

                // what to do in the background thread
                bw.DoWork += new DoWorkEventHandler(
                delegate(object o, DoWorkEventArgs args)
                {
                    BackgroundWorker b = o as BackgroundWorker;

                        String folderPath = this.folderBrowserDialog1.SelectedPath;

                        string prefix = manageFilePathsFile.GetPrefixForFilePathTextFile(tabControlName);
                        string fulltextFileLine = prefix + " - " + folderPath;

                        bool found = movieFilePaths_.Any(c => c == fulltextFileLine);
                        if (!found)
                        {
                            //temp list to hold the 1 path to send to the function 
                            List<string> addOnePath_ = new List<string>();
                            addOnePath_.Add(folderPath);

                            //add it to the master list of filepaths also

                            movieFilePaths_.Add(fulltextFileLine);
                            manageFilePathsFile.AddToFilePathTextFile(FILEPATH, folderPath, prefix);
                            // this allows another thread to call a item that was created / being managed by another thread                                
                            this.Invoke(new MethodInvoker(delegate()
                            {

                                manageFilePathsFile.PopulateListBoxWithFilePaths(listBoxMoviePaths, movieFilePaths_);

                            }));
                            //get the movies from that path 
                            List<Movie> tempMovieList_ = new List<Movie>();
                            tempMovieList_ = movie.GetMoviesFromNewPath(folderPath);
                            //adds the 2 lists together
                            movieList_.AddRange(tempMovieList_);
                            //http://tech.pro/tutorial/776/csharp-tutorial-binding-a-datagridview-to-a-collection
                            //http://stackoverflow.com/questions/9758577/c-sharp-datagridview-not-updated-when-datasource-is-changed
                            tempMovieList_.Clear();
                        }
                    }
                );//  bw.DoWork += new DoWorkEventHandler(delegate(object o, DoWorkEventArgs args

                // what to do when progress changed (update the progress bar for example)


                bw.ProgressChanged += new ProgressChangedEventHandler(
                delegate(object o, ProgressChangedEventArgs args)
                {


                });
                //bw1.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
                // bw.ProgressChanged += delegate { ... };


                // what to do when worker completes its task (notify the user)
                bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(
                delegate(object o, RunWorkerCompletedEventArgs args)
                {

                    //reset the data grid view
                    movieList_ = movieList_.OrderBy(x => x.FileName).ToList();
                    dataGridView1.DataSource = null;
                    dataGridView1.DataSource = movieList_;

                    //update the Interface outputs
                    // eg Movie Count: {count}
                    interfaceOutputs.PopulateInterfaceOutputs(dataGridView1, labelDataGridMovies);
                });

                bw.RunWorkerAsync();

                // this allows our worker to report progress during work
                bw.WorkerReportsProgress = true;

Recommended Answers

All 4 Replies

Essentially yes, break down your code into tasks that you can run in a method. You can give the background worker a method to execute (that's all a delegate is) and run it that way.

Be careful about altering UI components. That has to be done on the Main thread and you can easily lock your UI up that way.

A better suggestion might be to look at the Task namespace and the async keyword.

I'd also look at your design and split code into Data Load/Data Process/Date Presentation rather than having a single method do all the work.

commented: Excellent advise +15

Sweet cheers for the pointers,I will take th UI stuff out and out in in the main thread.

I will also take the presentation stuff out and put that separate.

Could you show me how to do this delegate stuff, I don't understand the examples I have read.

I am not a dev and this is a home project to organise my Movies, TV Shows, Music Videos and Rugby game collections that are spread across 2 or 3 locations into 1 central source.

You actually used a delegate in your second code section:

bw.DoWork += new DoWorkEventHandler(
---> delegate(object o, DoWorkEventArgs args) <----
{

Delegates are (at a basic level) method pointers. They allow you to pass methods around as arguments.

To use delegates properly, you should define them first. So to define the delegate above:

public delegate void BackgroundWorkerDelegate(object o, DoWorkEventArgs args);

Now in your class definitions if you declare a method with the same parameters, you can refer to it using your delegate definition (just like an object)

public void CalculatePathsBackground(object stateObject, DoWorkEventArgs eventArgs)
{
    /* I've renamed the variables to highlight that they onkly have to be the same types, not the same names */
    // Do work here
}

So now in your main class you could:

public void DoingStuff()
{
    BackgroundWorkerDelegate getPathsWorker = this.CalculatePathsBackground;

    BackgroundWorker bw = new BackgroundWorker();
    bw.DoWork += new DoWorkEventHandler(getPathsWorker);

    bw.RunWorkerAsync();
}

That's pretty much a crash course in delegates. There are better ways to design this and there are several considerations you should take into account. Personally, if you can use .NET 4/4.5 I'd start using the Task library.

If you want to learn a bit more about async, see my post here I've written a small tutorial and example.

Also, whilst you might say you're not a developer, you've done pretty well so far. The fact that you've got this far makes you a developer. :P

Ahh BackgroundWorkers, coding made easy.

The best way to keep these clear is to call function, however, you can put the code needed in the DoWork event for the BackgroundWorker (well actually you need to DoWorker to execute what you want done ... at least I have never seen it done otherways).

Now, I see you want to edit the UI, which as pointed above can't be down in the BackgroundWorker. It's a different thread then the one that created the item, however, ther are ways to Invoke it.

One is to use the ProgressChange event tied to the BackgroundWorker, when called it allows for updates to the. In your DoWork event you need two lines

BackgroundWorker worker = sender as BackgroundWorker;

worker.ReportProgress(0);

call the first at the beginning of the function, it's easier that way. Now the 0 can be a int or other parameters ... however, for other parameters, you have to set up like an object array or list. If you curious I can offer more on that.

The other way to update the UI is to Invoke access. If you are using newer versions of .NET (I think this came around in 3.5 or 4.0 ... but done quote me on that), you can do something very simple. Use code such as the following.

richTextBox1.Invoke(new Action(() => 
{ 
    richTextBox1.AppendText("Append some text");
    richTextBox1.SelectionStart = richTextBox1.Text.Length; //forces to scroll to bottom
    richTextBox1.Focus();
}));

Now, I am trying to recall my knowlegde of locks, but if I recall right, Invoking pretty much gives control when avaialable, so theoretically speaking, it will lock down the UI items to one thread .... however if you are updating other data like variables, it is wise to use locks.

Okay so that's just a quick run down on some stuff. Let me know if you want ot learn more about BackgroundWorkers, I have a lot of code I have learned working with them, and nice little tricks. Also if you are curious about threading, ask away. I love Threading, it's a very cool concept that I seem to implement more and more. (I won't bog this post down but feel free to message me or whatever and I'll get back to you)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.