Reputation: 1
To begin with, I'm relatively new to programming. I went through some introductory C# training for my new job, and it's the first language I've worked with.
I recently had a business problem that I decided to solve using C#, both to save time (I had hoped) and to learn more C# in the process. The business problem I mentioned was this: I had 600+ Word files that I needed to audit. For each document, I had to make sure that...
It would have been fastest to have my program iterate through all of the documents, making changes as it went along. But because of the nature of this assignment I wanted to make the changes manually, limiting the program's use to generating a list of files (out of the 600) where changes were necessary, and detailing what changes needed to be made for each of those files.
So, I have a button that calls up a FolderBrowserDialog.
private void AddFolderButtonClick(object sender, EventArgs e)
{
var folderBrowser = new FolderBrowserDialog();
if (folderBrowser.ShowDialog() != DialogResult.OK)
{
return;
}
this.progressBar1.Visible = true;
this.progressBar1.Style = ProgressBarStyle.Marquee;
this.Cursor = Cursors.WaitCursor;
var args = new List<string>(Directory.EnumerateDirectories(folderBrowser.SelectedPath));
// Get list of files in selected directory, adding to list of directories
args.AddRange(Directory.EnumerateFiles(folderBrowser.SelectedPath));
this.displayListBox.BeginUpdate();
foreach (string path in args)
{
if (File.Exists(path))
{
// This path is a file
this.ProcessFile(Path.GetFullPath(path));
}
else if (Directory.Exists(path))
{
// This path is a directory
this.ProcessDirectory((Path.GetFullPath(path)));
}
else
{
Console.WriteLine(Resources.Finder_Invalid_File_Or_Directory, path);
}
}
this.displayListBox.EndUpdate();
this.progressBar1.Visible = false;
this.progressBar1.Style = ProgressBarStyle.Continuous;
this.Cursor = Cursors.Default;
}
Together, the following two methods iterate through all subdirectories and files to create a full list of all files below the top level directory selected through the FolderBrowserDialog:
private void ProcessDirectory(string targetDirectory)
{
// Process the list of files found in the directory.
string[] fileEntries = Directory.GetFiles(targetDirectory);
foreach (string fileName in fileEntries)
{
this.ProcessFile(fileName);
}
// Recurse into subdirectories of this directory.
string[] subdirectoryEntries = Directory.GetDirectories(targetDirectory);
foreach (string subdirectory in subdirectoryEntries)
{
this.ProcessDirectory(subdirectory);
}
}
private void ProcessFile(string path)
{
Console.WriteLine(Resources.Finder_File_Processed, path);
string fileName = Path.GetFileName(path);
if (fileName == null || fileName.StartsWith(@"~$") || this.selectedFilesList.Contains(path))
{
return;
}
this.selectedFilesList.Add(path);
this.filePathsCountLabel.Text = (@"Count: " + this.selectedFilesList.Count);
this.displayListBox.Items.Add(path);
}
Once all this code has run, I get a full list of documents. I click a button and the program does what it's supposed to from here on out. Okay, cool. I mentioned before that half of the reason I chose to use C# to solve this was for the sake of learning. At this point I've got everything I need but what I really want to know is how can I implement threading to make the GUI responsive while the list of files is being generated? I've looked through several examples. They made sense. For some reason I just can't get my head around it for this application though. How can I make the whole process of processing subdirectories and files happen without locking up the GUI?
Upvotes: 0
Views: 198
Reputation: 112
You have to create a separate thread to process your work. Look at this if you are using .NET 4.0+ or this for older versions.
With Task, you can write
Task.Factory.StartNew(() => DoAction()
where DoAction is your function that starts to process data.
But do not forget to use Invoke, if you want to act with GUI from separate thread. For example, if you want to update some Label text from separate thread, you have to do this
label1.Invoke(() => label1.Text = "Some Text");
Upvotes: 0
Reputation: 1258
I believe what you need could be found here. In short, to use a backgroundworker which does all the work on a separate thread thus prevents GUI freezes, first you instantiate BackgroundWorker and handle the DoWork event. Then you call RunWorkerAsync, optionally with an object argument.
As a skeleton code:
class myClass
{
static BackgroundWorker myBw = new BackgroundWorker();
static void Main()
{
myBw .DoWork += myBw_DoWork;
myBw .RunWorkerAsync ("an argument here");
Console.ReadLine();
}
static void myBw_DoWork (object sender, DoWorkEventArgs e)
{
// This is called on the separate thread, argument is called as e.Argument
// Perform heavy task...
}
}
Upvotes: 1