Følgende eksempel viser hvorledes løsningen fra "arne v" kan anvendes sammen med en BackgroundWorker:
namespace FileSearch
{
using System;
using System.IO;
using System.ComponentModel;
using System.Windows.Forms;
using System.Globalization;
public partial class SearchDialog : Form
{
private BackgroundWorker backgroundWorker;
// This delegate enables asynchronous calls for setting the result on the ListView control.
private delegate void AddResultCallback(string text);
// This delegate enables asynchronous calls for setting the text on the status label.
private delegate void SetMessageCallback(string text);
public SearchDialog()
{
InitializeComponent();
this.AcceptButton = this.buttonSearch;
this.buttonSearch.Enabled = true;
this.buttonCancel.Enabled = false;
#region FolderBrowserDialog
this.folderBrowserDialog.SelectedPath = @"C:\";
this.folderBrowserDialog.ShowNewFolderButton = false;
this.folderBrowserDialog.RootFolder = Environment.SpecialFolder.MyComputer;
#endregion // FolderBrowserDialog
this.textBoxLookIn.Text = this.folderBrowserDialog.SelectedPath;
this.InitializeBackgoundWorker();
}
#region BackgroundWorker
/// <summary>
// Set up the BackgroundWorker object by attaching event handlers.
/// </summary>
private void InitializeBackgoundWorker()
{
this.backgroundWorker = new BackgroundWorker();
this.backgroundWorker.WorkerSupportsCancellation = true;
this.backgroundWorker.DoWork += new DoWorkEventHandler(BackgroundWorkerDoWork);
this.backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(BackgroundWorkerRunWorkerCompleted);
}
private void BackgroundWorkerDoWork(object sender, DoWorkEventArgs doWorkEventArgs)
{
// Get the BackgroundWorker that raised this event.
BackgroundWorker backgroundWorker = sender as BackgroundWorker;
this.SetMessage("Searching...");
// Assign the result of the computation to the Result property of the DoWorkEventArgs
// object. This is will be available to the RunWorkerCompleted eventhandler.
// doWorkEventArgs.Result = this.Search(backgroundWorker, doWorkEventArgs /*, Parameter (Optional)*/ );
this.Search(backgroundWorker, doWorkEventArgs /*, Parameter (Optional)*/ );
}
private void BackgroundWorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs runWorkerCompletedEventArgs)
{
// First, handle the case where an exception was thrown.
if (runWorkerCompletedEventArgs.Error != null)
{
this.SetMessage("Error: " + runWorkerCompletedEventArgs.Error.Message);
}
else if (runWorkerCompletedEventArgs.Cancelled)
{
// Next, handle the case where the user canceled the operation.
// Note that due to a race condition in the DoWork event handler, the Cancelled
// flag may not have been set, even though CancelAsync was called.
this.SetMessage("Canceled");
}
else
{
// Finally, handle the case where the operation succeeded.
this.SetMessage("Search Ended");
}
// Enable the Start button.
this.buttonSearch.Enabled = true;
// Disable the Cancel button.
this.buttonCancel.Enabled = false;
}
#endregion // BackgroundWorker
private void ButtonSearchClick(object sender, EventArgs e)
{
this.listViewResults.Items.Clear();
// Disable the Search button until the asynchronous operation is done.
this.buttonSearch.Enabled = false;
// Enable the Cancel button while the asynchronous operation runs.
this.buttonCancel.Enabled = true;
// Start the asynchronous operation.
// this.backgroundWorker.RunWorkerAsync(parameter (optional));
this.backgroundWorker.RunWorkerAsync();
}
private void ButtonCancelClick(object sender, EventArgs e)
{
this.backgroundWorker.CancelAsync();
// Disable the Cancel button.
this.buttonCancel.Enabled = false;
}
private void ButtonDirectoryClick(object sender, EventArgs e)
{
DialogResult dialogResult = this.folderBrowserDialog.ShowDialog();
if (dialogResult == DialogResult.OK)
{
this.textBoxLookIn.Text = this.folderBrowserDialog.SelectedPath;
}
}
// This is the method that does the actual work. For this
// example, it computes a Fibonacci number and
// reports progress as it does its work.
private void Search(BackgroundWorker backgroundWorker, DoWorkEventArgs doWorkEventArgs /*, Parameter (Optional)*/)
{
this.Lookup(this.textBoxLookIn.Text, backgroundWorker, doWorkEventArgs);
}
private void Lookup(String directory, BackgroundWorker backgroundWorker, DoWorkEventArgs doWorkEventArgs)
{
if (backgroundWorker.CancellationPending)
{
doWorkEventArgs.Cancel = true;
return;
}
else
{
try
{
string[] files = Directory.GetFiles(directory, "*.cs");
foreach (string file in files)
{
this.AddResult(file);
}
string[] directories = Directory.GetDirectories(directory);
foreach (string d in directories)
{
this.Lookup(d, backgroundWorker, doWorkEventArgs);
}
}
catch (ArgumentException argumentException)
{
MessageBox.Show(String.Format(CultureInfo.CurrentUICulture, "Unable to search.\nReason: {0}", argumentException.Message), "Search Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
catch (UnauthorizedAccessException unauthorizedAccessException)
{
this.AddResult(unauthorizedAccessException.Message);
}
catch (DirectoryNotFoundException directoryNotFoundException)
{
this.AddResult("*** Unknown Directory: " + directoryNotFoundException.Message);
}
}
}
/// <summary>
/// This method demonstrates a pattern for making thread-safe calls on a Windows Forms control.
///
/// If the calling thread is different from the thread that
/// created the TextBox control, this method creates a SetTextCallback and calls itself asynchronously using the
/// Invoke method.
///
/// If the calling thread is the same as the thread that created
/// the TextBox control, the Text property is set directly.
///
/// Read more on:
http://msdn2.microsoft.com/en-us/library/ms171728.aspx /// </summary>
/// <param name="text">Text to be added to the list.</param>
private void AddResult(string text)
{
// InvokeRequired required compares the thread ID of the calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.listViewResults.InvokeRequired)
{
AddResultCallback setTextCallback = new AddResultCallback(AddResult);
this.Invoke(setTextCallback, new object[] { text });
}
else
{
this.listViewResults.Items.Add(text);
}
}
/// <summary>
/// This method demonstrates a pattern for making thread-safe calls on a Windows Forms control.
///
/// If the calling thread is different from the thread that
/// created the TextBox control, this method creates a SetTextCallback and calls itself asynchronously using the
/// Invoke method.
///
/// If the calling thread is the same as the thread that created
/// the TextBox control, the Text property is set directly.
///
/// Read more on:
http://msdn2.microsoft.com/en-us/library/ms171728.aspx /// </summary>
/// <param name="text">Text to be added to the list.</param>
private void SetMessage(string text)
{
// InvokeRequired required compares the thread ID of the calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.labelMessage.InvokeRequired)
{
SetMessageCallback setMessageCallback = new SetMessageCallback(SetMessage);
this.Invoke(setMessageCallback, new object[] { text });
}
else
{
this.labelMessage.Text = text;
}
}
}
}