How to program Windows Forms: Use a background thread to search for files (typical example of a thread)

Source: Internet
Author: User
Tags win32 window
Windows form Programming
How to: use background threads to search for files

Component replaced Namespace and added features, but you can also choose to retainSystem. ThreadingNamespace for backward compatibility and future use. For more information, see BackgroundWorker component overview.

"Windows Forms" uses the single-thread unit (STA) model, because "Windows Forms" are based on the Win32 window of the Local Machine, while the Win32 window is essentially a unit thread. The STA model means that a window can be created on any thread, but once the window is created, the thread cannot be switched, and all function calls to it must occur on the Creation thread. In addition to Windows Forms, classes in. NET Framework use free-threaded models. For information about thread processing in. NET Framework, see .

The STA model requires that any method on the control that needs to be called from the non-creation thread of the control must be blocked and delivered (executed on it) to the creation thread of the control. For this purpose, the base class Provides several methods ( , And ). Call the synchronous method, while Call the Asynchronous Method.

If you use multiple threads for a task that occupies a large amount of resources in the control, the user interface can execute a computing task that occupies a large amount of resources on the background thread while maintaining a responsive response.

The following example (DirectorySearcherA multi-threaded Windows form control that uses the background thread to Recursively search for a directory to find the file that matches the specified search string, and then fills the list box with the search result. The main concepts explained in this example are as follows:

  • DirectorySearcherStart the new thread for search. This thread executesThreadProcedureMethod, and this method calls the HelperRecurseDirectoryMethod to perform the actual search and fill in the list box. However, filling the list box requires calling between threads. The following two items are described.

  • DirectorySearcherDefinitionAddFilesMethod to add the file to the list box; however,RecurseDirectoryCannot be called directlyAddFilesBecauseAddFilesYou can only createDirectorySearcher.

  • RecurseDirectoryYesAddFilesThe only way is through cross-thread call, that is, by callingInvokeOrBeginInvokeSetAddFilesMailDirectorySearcher.RecurseDirectoryUseBeginInvokeSo that the call can be executed asynchronously.

  • To mail a method, the function pointer or callback is required. This is implemented through delegation in. NET Framework.BeginInvokeUse delegation as the parameter.DirectorySearcherTherefore, the delegate (FileListDelegateIn the constructorAddFilesBindFileListDelegateAnd pass the delegated instanceBeginInvoke. When the search is complete,DirectorySearcherIt also defines the event Delegate for sending.

Namespace Microsoft. Samples. DirectorySearcher
{
Using System;
Using System. IO;
Using System. Threading;
Using System. Windows. Forms;

/// <Summary>
/// This class is a Windows Forms control that implements a simple directory searcher.
/// You provide, through code, a search string and it will search directories on
/// A background thread, populating its list box with matches.
/// </Summary>
Public class DirectorySearcher: Control
{
// Define a special delegate that handles implements aling
// Lists of file names from the background directory search
// Thread to the thread that contains the list box.
Private delegate void FileListDelegate (string [] files, int startIndex, int count );

Private ListBox listBox;
Private string searchCriteria;
Private bool searching;
Private bool deferSearch;
Private Thread searchThread;
Private FileListDelegate fileListDelegate;
Private EventHandler onSearchComplete;

Public DirectorySearcher ()
{
ListBox = new ListBox ();
ListBox. Dock = DockStyle. Fill;

Controls. Add (listBox );

FileListDelegate = new FileListDelegate (AddFiles );
OnSearchComplete = new EventHandler (OnSearchComplete );
}

Public string SearchCriteria
{
Get
{
Return searchCriteria;
}
Set
{
// If currently searching, abort
// The search and restart it after
// Setting the new criteria.
//
Bool wasSearching = Searching;

If (wasSearching)
{
StopSearch ();
}

ListBox. Items. Clear ();
SearchCriteria = value;

If (wasSearching)
{
BeginSearch ();
}
}
}

Public bool Searching
{
Get
{
Return searching;
}
}

Public event EventHandler SearchComplete;

/// <Summary>
/// This method is called from the background thread. It is called through
/// A BeginInvoke call so that it is always passed aled to the thread that
/// Owns the list box control.
/// </Summary>
/// <Param name = "files"> </param>
/// <Param name = "startIndex"> </param>
/// <Param name = "count"> </param>
Private void AddFiles (string [] files, int startIndex, int count)
{
While (count --> 0)
{
ListBox. Items. Add (files [startIndex + count]);
}
}

Public void BeginSearch ()
{
// Create the search thread, which
// Will begin the search.
// If already searching, do nothing.
//
If (Searching)
{
Return;
}

// Start the search if the handle has
// Been created. Otherwise, defer it until
// Handle has been created.
If (IsHandleCreated)
{
SearchThread = new Thread (new ThreadStart (ThreadProcedure ));
Searching = true;
SearchThread. Start ();
}
Else
{
DeferSearch = true;
}
}

Protected override void OnHandleDestroyed (EventArgs e)
{
// If the handle is being destroyed and you are not
// Recreating it, then abort the search.
If (! RecreatingHandle)
{
StopSearch ();
}
Base. OnHandleDestroyed (e );
}

Protected override void OnHandleCreated (EventArgs e)
{
Base. OnHandleCreated (e );
If (deferSearch)
{
DeferSearch = false;
BeginSearch ();
}
}

/// <Summary>
/// This method is called by the background thread when it has finished
/// The search.
/// </Summary>
/// <Param name = "sender"> </param>
/// <Param name = "e"> </param>
Private void OnSearchComplete (object sender, EventArgs e)
{
If (SearchComplete! = Null)
{
SearchComplete (sender, e );
}
}

Public void StopSearch ()
{
If (! Searching)
{
Return;
}

If (searchThread. IsAlive)
{
SearchThread. Abort ();
SearchThread. Join ();
}

SearchThread = null;
Searching = false;
}

/// <Summary>
/// Recurses the given path, adding all files on that path
/// The list box. After it finishes with the files, it
/// Callitself once for each directory on the path.
/// </Summary>
/// <Param name = "searchPath"> </param>
Private void RecurseDirectory (string searchPath)
{
// Split searchPath into a directory and a wildcard specification.
//
String directory = Path. GetDirectoryName (searchPath );
String search = Path. GetFileName (searchPath );

// If a directory or search criteria are not specified, then return.
//
If (directory = null | search = null)
{
Return;
}

String [] files;

// File systems like NTFS that have
// Access permissions might result in exceptions
// When looking into directories without permission.
// Catch those exceptions and return.
Try
{
Files = Directory. GetFiles (directory, search );
}
Catch (UnauthorizedAccessException)
{
Return;
}
Catch (DirectoryNotFoundException)
{
Return;
}

// Perform a BeginInvoke call to the list box
// In order to specify Al to the correct thread. It is not
// Very efficient to perform this has al once for every
// File, so batch up multiple file callinto one
// Marshal invocation.
Int startingIndex = 0;

While (startingIndex <files. Length)
{
// Batch up 20 files at once, unless at
// End.
//
Int count = 20;
If (count + startingIndex> = files. Length)
{
Count = files. Length-startingIndex;
}

// Begin the cross-thread call. Because you are passing
// Immutable objects into this invoke method, you do not have
// Wait for it to finish. If these were complex objects, you wowould
// Have to either create new instances of them or
// Wait for the thread to process this invoke before modifying
// The objects.
IAsyncResult r = BeginInvoke (fileListDelegate, new object [] {files, startingIndex, count });
StartingIndex + = count;
}

// Now that you have finished the files in this directory, recurse
// Each subdirectory.
String [] directories = Directory. GetDirectories (directory );
Foreach (string d in directories)
{
RecurseDirectory (Path. Combine (d, search ));
}
}

/// <Summary>
/// This is the actual thread procedure. This method runs in a background
/// Thread to scan directories. When finished, it simply exits.
/// </Summary>
Private void ThreadProcedure ()
{
// Get the search string. Individual
// Field assigns are atomic in. NET, so you do not
// Need to use any thread synchronization to grab
// The string value here.
Try
{
String localSearch = SearchCriteria;

// Now, search the file system.
//
RecurseDirectory (localSearch );
}
Finally
{
// You are done with the search, so update.
//
Searching = false;

// Raise an event that notifies the user that
// The search has terminated.
// You do not have to do this through a pair aled call,
// Financialing is recommended for the following reason:
// Users of this control do not know that it is
// Multithreaded, so they until CT its events
// Come back on the same thread as the control.
BeginInvoke (onSearchComplete, new object [] {this, EventArgs. Empty });
}
}
}
}

Use multi-threaded controls on Forms

The following example shows how to use multithreading on a form.DirectorySearcherControl.

Namespace SampleUsage
{
Using Microsoft. Samples. DirectorySearcher;
Using System;
Using System. Drawing;
Using System. Collections;
Using System. ComponentModel;
Using System. Windows. Forms;
Using System. Data;

/// <Summary>
/// Summary description for Form1.
/// </Summary>
Public class Form1: System. Windows. Forms. Form
{
Private DirectorySearcher directorySearcher;
Private System. Windows. Forms. TextBox searchText;
Private System. Windows. Forms. Label searchLabel;
Private System. Windows. Forms. Button searchButton;

Public Form1 ()
{
//
// Required for Windows Forms designer support.
//
InitializeComponent ();

//
// Add any constructor code after InitializeComponent call here.
//
}

# Region Windows Form Designer generated code
/// <Summary>
/// Required method for designer support. Do not modify
/// The contents of this method with the code editor.
/// </Summary>
Private void InitializeComponent ()
{
This. directorySearcher = new Microsoft. Samples. DirectorySearcher. DirectorySearcher ();
This. searchButton = new System. Windows. Forms. Button ();
This. searchText = new System. Windows. Forms. TextBox ();
This. searchLabel = new System. Windows. Forms. Label ();
This. directorySearcher. Anchor = (System. Windows. Forms. AnchorStyles. Top | System. Windows. Forms. AnchorStyles. Bottom)
| System. Windows. Forms. AnchorStyles. Left)
| System. Windows. Forms. AnchorStyles. Right );
This. directorySearcher. Location = new System. Drawing. Point (8, 72 );
This. directorySearcher. SearchCriteria = null;
This. directorySearcher. Size = new System. Drawing. Size (271,173 );
This. directorySearcher. TabIndex = 2;
This. directorySearcher. SearchComplete + = new System. EventHandler (this. directorySearcher_SearchComplete );
This. searchButton. Location = new System. Drawing. Point (8, 16 );
This. searchButton. Size = new System. Drawing. Size (88, 40 );
This. searchButton. TabIndex = 0;
This. searchButton. Text = "& Search ";
This. searchButton. Click + = new System. EventHandler (this. searchButton_Click );
This. searchText. Anchor = (System. Windows. Forms. AnchorStyles. Top | System. Windows. Forms. AnchorStyles. Left)
| System. Windows. Forms. AnchorStyles. Right );
This. searchText. Location = new System. Drawing. Point (104, 24 );
This. searchText. Size = new System. Drawing. Size (175, 20 );
This. searchText. TabIndex = 1;
This. searchText. Text = "c: \ *. cs ";
This. searchLabel. ForeColor = System. Drawing. Color. Red;
This. searchLabel. Location = new System. Drawing. Point (104, 48 );
This. searchLabel. Size = new System. Drawing. Size (176, 16 );
This. searchLabel. TabIndex = 3;
This. ClientSize = new System. Drawing. Size (291,264 );
This. Controls. AddRange (new System. Windows. Forms. Control [] {this. searchLabel,
This. directorySearcher,
This. searchText,
This. searchButton });
This. Text = "Search Directories ";

}
# Endregion

/// <Summary>
/// The main entry point for the application.
/// </Summary>
[STAThread]
Static void Main ()
{
Application. Run (new Form1 ());
}

Private void searchButton_Click (object sender, System. EventArgs e)
{
DirectorySearcher. SearchCriteria = searchText. Text;
SearchLabel. Text = "Searching ...";
DirectorySearcher. BeginSearch ();
}

Private void directorySearcher_SearchComplete (object sender, System. EventArgs e)
{
SearchLabel. Text = string. Empty;
}
}
}

Reference from:
Ms-help: // MS. MSDNQTR. v80.chs/MS. MSDN. v80/MS. VisualStudio. v80.chs/dv_fxmclictl/html/Examples

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.