Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Ez a cikk bemutatja, hogyan hozhat létre adatfolyamblokkokból álló hálózatot, amely képfeldolgozást végez egy Windows Forms alkalmazásban.
Ez a példa betölti a képfájlokat a megadott mappából, létrehoz egy összetett képet, és megjeleníti az eredményt. A példa az adatfolyam-modellel irányítja át a képeket a hálózaton. Az adatfolyam-modellben a program független összetevői üzenetek küldésével kommunikálnak egymással. Amikor egy összetevő üzenetet kap, végrehajt egy műveletet, majd átadja az eredményt egy másik összetevőnek. Hasonlítsa össze ezt a vezérlőfolyamat-modellel, amelyben az alkalmazások vezérlőstruktúrákat, például feltételes utasításokat, hurkokat stb. használnak a programok műveleteinek sorrendjének szabályozásához.
Előfeltételek
Mielőtt elkezdené ezt az útmutatót, olvassa el az Adatfolyam elemet.
Megjegyzés
A TPL-adatfolyamtár (a System.Threading.Tasks.Dataflow névtér) nincs elosztva a .NET-tel. Ha telepíteni szeretné a névteret a System.Threading.Tasks.Dataflow Visual Studióban, nyissa meg a projektet, válassza a Project menü NuGet-csomagok kezelése elemét, és keressen rá online a System.Threading.Tasks.Dataflow csomagra. Másik lehetőségként futtassa dotnet add package System.Threading.Tasks.Dataflowa parancsot a .NET Core parancssori felülettel történő telepítéséhez.
Szakaszok
Ez az útmutató a következő szakaszokat tartalmazza:
A Windows Forms alkalmazás létrehozása
Ez a szakasz bemutatja, hogyan hozhatja létre az alapszintű Windows Forms alkalmazást, és hogyan adhat hozzá vezérlőket a főűrlaphoz.
A Windows Forms alkalmazás létrehozása
A Visual Studióban hozzon létre egy Visual C# vagy Visual Basic Windows Forms Application projektet. Ebben a dokumentumban a projekt neve
CompositeImages.A főűrlap Űrlap1.cs (Visual Basichez Form1.vb) űrlaptervezőjében adjon hozzá egy vezérlőt ToolStrip .
Adjon hozzá egy ToolStripButton vezérlőt a ToolStrip vezérlőhöz. Állítsa a tulajdonságot értékre DisplayStyleText , a Text tulajdonságot pedig a Mappa kiválasztása értékre.
Adjon hozzá egy második ToolStripButton vezérlőt a ToolStrip vezérlőhöz. Állítsa a tulajdonságot értékre DisplayStyleText, a Text tulajdonságot Mégse értékre, a Enabled tulajdonságot pedig értékre
False.PictureBox Objektum hozzáadása a főűrlaphoz. Állítsa a tulajdonságot értékre DockFill.
Az adatfolyam-hálózat létrehozása
Ez a szakasz a képfeldolgozást végző adatfolyam-hálózat létrehozását ismerteti.
Az adatfolyam-hálózat létrehozása
Adjon hozzá egy hivatkozást System.Threading.Tasks.Dataflow.dll a projekthez.
Győződjön meg arról, hogy a Form1.cs (Form1.vb for Visual Basic) tartalmazza a következő
using(UsingVisual Basic)-utasításokat:using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Threading.Tasks.Dataflow; using System.Windows.Forms;Adja hozzá a következő adattagokat az
Form1osztályhoz:// The head of the dataflow network. ITargetBlock<string> headBlock = null; // Enables the user interface to signal cancellation to the network. CancellationTokenSource cancellationTokenSource;Adja hozzá a következő metódust a
CreateImageProcessingNetworkosztályhozForm1. Ez a metódus létrehozza a képfeldolgozó hálózatot.// Creates the image processing dataflow network and returns the // head node of the network. ITargetBlock<string> CreateImageProcessingNetwork() { // // Create the dataflow blocks that form the network. // // Create a dataflow block that takes a folder path as input // and returns a collection of Bitmap objects. var loadBitmaps = new TransformBlock<string, IEnumerable<Bitmap>>(path => { try { return LoadBitmaps(path); } catch (OperationCanceledException) { // Handle cancellation by passing the empty collection // to the next stage of the network. return Enumerable.Empty<Bitmap>(); } }); // Create a dataflow block that takes a collection of Bitmap objects // and returns a single composite bitmap. var createCompositeBitmap = new TransformBlock<IEnumerable<Bitmap>, Bitmap>(bitmaps => { try { return CreateCompositeBitmap(bitmaps); } catch (OperationCanceledException) { // Handle cancellation by passing null to the next stage // of the network. return null; } }); // Create a dataflow block that displays the provided bitmap on the form. var displayCompositeBitmap = new ActionBlock<Bitmap>(bitmap => { // Display the bitmap. pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage; pictureBox1.Image = bitmap; // Enable the user to select another folder. toolStripButton1.Enabled = true; toolStripButton2.Enabled = false; Cursor = DefaultCursor; }, // Specify a task scheduler from the current synchronization context // so that the action runs on the UI thread. new ExecutionDataflowBlockOptions { TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext() }); // Create a dataflow block that responds to a cancellation request by // displaying an image to indicate that the operation is cancelled and // enables the user to select another folder. var operationCancelled = new ActionBlock<object>(delegate { // Display the error image to indicate that the operation // was cancelled. pictureBox1.SizeMode = PictureBoxSizeMode.CenterImage; pictureBox1.Image = pictureBox1.ErrorImage; // Enable the user to select another folder. toolStripButton1.Enabled = true; toolStripButton2.Enabled = false; Cursor = DefaultCursor; }, // Specify a task scheduler from the current synchronization context // so that the action runs on the UI thread. new ExecutionDataflowBlockOptions { TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext() }); // // Connect the network. // // Link loadBitmaps to createCompositeBitmap. // The provided predicate ensures that createCompositeBitmap accepts the // collection of bitmaps only if that collection has at least one member. loadBitmaps.LinkTo(createCompositeBitmap, bitmaps => bitmaps.Count() > 0); // Also link loadBitmaps to operationCancelled. // When createCompositeBitmap rejects the message, loadBitmaps // offers the message to operationCancelled. // operationCancelled accepts all messages because we do not provide a // predicate. loadBitmaps.LinkTo(operationCancelled); // Link createCompositeBitmap to displayCompositeBitmap. // The provided predicate ensures that displayCompositeBitmap accepts the // bitmap only if it is non-null. createCompositeBitmap.LinkTo(displayCompositeBitmap, bitmap => bitmap != null); // Also link createCompositeBitmap to operationCancelled. // When displayCompositeBitmap rejects the message, createCompositeBitmap // offers the message to operationCancelled. // operationCancelled accepts all messages because we do not provide a // predicate. createCompositeBitmap.LinkTo(operationCancelled); // Return the head of the network. return loadBitmaps; }Implementálja a metódust
LoadBitmaps.// Loads all bitmap files that exist at the provided path. IEnumerable<Bitmap> LoadBitmaps(string path) { List<Bitmap> bitmaps = new List<Bitmap>(); // Load a variety of image types. foreach (string bitmapType in new string[] { "*.bmp", "*.gif", "*.jpg", "*.png", "*.tif" }) { // Load each bitmap for the current extension. foreach (string fileName in Directory.GetFiles(path, bitmapType)) { // Throw OperationCanceledException if cancellation is requested. cancellationTokenSource.Token.ThrowIfCancellationRequested(); try { // Add the Bitmap object to the collection. bitmaps.Add(new Bitmap(fileName)); } catch (Exception) { // TODO: A complete application might handle the error. } } } return bitmaps; }Implementálja a metódust
CreateCompositeBitmap.// Creates a composite bitmap from the provided collection of Bitmap objects. // This method computes the average color of each pixel among all bitmaps // to create the composite image. Bitmap CreateCompositeBitmap(IEnumerable<Bitmap> bitmaps) { Bitmap[] bitmapArray = bitmaps.ToArray(); // Compute the maximum width and height components of all // bitmaps in the collection. Rectangle largest = new Rectangle(); foreach (var bitmap in bitmapArray) { if (bitmap.Width > largest.Width) largest.Width = bitmap.Width; if (bitmap.Height > largest.Height) largest.Height = bitmap.Height; } // Create a 32-bit Bitmap object with the greatest dimensions. Bitmap result = new Bitmap(largest.Width, largest.Height, PixelFormat.Format32bppArgb); // Lock the result Bitmap. var resultBitmapData = result.LockBits( new Rectangle(new Point(), result.Size), ImageLockMode.WriteOnly, result.PixelFormat); // Lock each source bitmap to create a parallel list of BitmapData objects. var bitmapDataList = (from bitmap in bitmapArray select bitmap.LockBits( new Rectangle(new Point(), bitmap.Size), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb)) .ToList(); // Compute each column in parallel. Parallel.For(0, largest.Width, new ParallelOptions { CancellationToken = cancellationTokenSource.Token }, i => { // Compute each row. for (int j = 0; j < largest.Height; j++) { // Counts the number of bitmaps whose dimensions // contain the current location. int count = 0; // The sum of all alpha, red, green, and blue components. int a = 0, r = 0, g = 0, b = 0; // For each bitmap, compute the sum of all color components. foreach (var bitmapData in bitmapDataList) { // Ensure that we stay within the bounds of the image. if (bitmapData.Width > i && bitmapData.Height > j) { unsafe { byte* row = (byte*)(bitmapData.Scan0 + (j * bitmapData.Stride)); byte* pix = (byte*)(row + (4 * i)); a += *pix; pix++; r += *pix; pix++; g += *pix; pix++; b += *pix; } count++; } } //prevent divide by zero in bottom right pixelless corner if (count == 0) break; unsafe { // Compute the average of each color component. a /= count; r /= count; g /= count; b /= count; // Set the result pixel. byte* row = (byte*)(resultBitmapData.Scan0 + (j * resultBitmapData.Stride)); byte* pix = (byte*)(row + (4 * i)); *pix = (byte)a; pix++; *pix = (byte)r; pix++; *pix = (byte)g; pix++; *pix = (byte)b; } } }); // Unlock the source bitmaps. for (int i = 0; i < bitmapArray.Length; i++) { bitmapArray[i].UnlockBits(bitmapDataList[i]); } // Unlock the result bitmap. result.UnlockBits(resultBitmapData); // Return the result. return result; }Megjegyzés
A metódus C#-verziója
CreateCompositeBitmapmutatókkal teszi lehetővé az System.Drawing.Bitmap objektumok hatékony feldolgozását. Ezért a nem biztonságos kulcsszó használatához engedélyeznie kell a nem biztonságos kód engedélyezése beállítást a projektben. A nem biztonságos kód Visual C#-projektekben való engedélyezéséről további információt a Build Page, Project Tervező (C#) című témakörben talál.
Az alábbi táblázat a hálózat tagjait ismerteti.
| Tag | Típus | Leírás |
|---|---|---|
loadBitmaps |
TransformBlock<TInput,TOutput> | Bemenetként egy mappaelérési Bitmap utat vesz fel, és kimenetként objektumgyűjteményt hoz létre. |
createCompositeBitmap |
TransformBlock<TInput,TOutput> | Bemenetként egy objektumgyűjteményt Bitmap vesz fel, és kimenetként összetett bitképet hoz létre. |
displayCompositeBitmap |
ActionBlock<TInput> | Megjeleníti az összetett bitképet az űrlapon. |
operationCancelled |
ActionBlock<TInput> | Egy képet jelenít meg, amely jelzi, hogy a művelet megszakadt, és lehetővé teszi a felhasználó számára egy másik mappa kiválasztását. |
Az adatfolyamblokkok hálózat létrehozásához való csatlakoztatásához ez a példa a metódust LinkTo használja. A LinkTo metódus egy túlterhelt verziót tartalmaz, amely egy Predicate<T> objektumot fogad el, amely meghatározza, hogy a célblokk elfogad-e vagy elutasít egy üzenetet. Ez a szűrési mechanizmus lehetővé teszi, hogy az üzenetblokkok csak bizonyos értékeket fogadjanak. Ebben a példában a hálózat kétféleképpen ágazhat el. A főág betölti a lemezképeket, létrehozza az összetett képet, és megjeleníti a képet az űrlapon. A másodlagos ág megszakítja az aktuális műveletet. Az Predicate<T> objektumok lehetővé teszik, hogy az adatfolyam-blokkok a főág mentén válthassanak az alternatív ágra bizonyos üzenetek elutasításával. Ha például a felhasználó megszakítja a műveletet, az adatfolyam-blokk createCompositeBitmap kimenete null (Nothing Visual Basicben) lesz. Az adatfolyam-blokk displayCompositeBitmap elutasítja a null bemeneti értékeket, ezért a rendszer felajánlja az üzenetet a számára operationCancelled. Az adatfolyam-blokk operationCancelled minden üzenetet elfogad, ezért megjelenít egy képet, amely jelzi a művelet megszakítását.
Az alábbi ábrán a képfeldolgozó hálózat látható:
Mivel a és operationCancelled az displayCompositeBitmap adatfolyam blokkok a felhasználói felületen működnek, fontos, hogy ezek a műveletek a felhasználói felület szálán történjenek. Ennek érdekében az építés során ezek az objektumok egy objektumot ExecutionDataflowBlockOptions biztosítanak, amelynek TaskScheduler tulajdonsága értékre TaskScheduler.FromCurrentSynchronizationContextvan állítva. A TaskScheduler.FromCurrentSynchronizationContext metódus létrehoz egy TaskScheduler objektumot, amely az aktuális szinkronizálási környezetben végez munkát. Mivel a metódus a CreateImageProcessingNetwork felhasználói felületi szálon futó Mappa kiválasztása gomb kezelőjéből van meghívva, a és operationCancelled adatfolyam-blokkok műveletei displayCompositeBitmap is a felhasználói felület szálán futnak.
Ez a példa megosztott lemondási jogkivonatot használ a CancellationToken tulajdonság beállítása helyett, mivel a tulajdonság véglegesen megszakítja az CancellationToken adatfolyamblokkok végrehajtását. A lemondási jogkivonat lehetővé teszi, hogy ez a példa többször is újra felhasználja ugyanazt az adatfolyam-hálózatot, még akkor is, ha a felhasználó megszakít egy vagy több műveletet. Egy adatfolyam-blokk végrehajtásának végleges megszakítására szolgáló CancellationToken példa : How to: Cancel a Dataflow Block (Adatfolyam-blokk megszakítása).
Az adatfolyam-hálózat csatlakoztatása a felhasználói felülethez
Ez a szakasz azt ismerteti, hogyan csatlakoztathatja az adatfolyam-hálózatot a felhasználói felülethez. Az összetett rendszerkép létrehozását és a művelet megszakítását a Mappa kiválasztása és a Mégse gomb indítja el. Ha a felhasználó ezen gombok bármelyikét választja, a megfelelő műveletet aszinkron módon indítja el a rendszer.
Az adatfolyam-hálózat csatlakoztatása a felhasználói felülethez
A főűrlap űrlaptervezőjében hozzon létre egy eseménykezelőt az Click eseményhez a Mappa kiválasztása gombhoz.
Implementálja a ClickMappa kiválasztása gomb eseményét.
// Event handler for the Choose Folder button. private void toolStripButton1_Click(object sender, EventArgs e) { // Create a FolderBrowserDialog object to enable the user to // select a folder. FolderBrowserDialog dlg = new FolderBrowserDialog { ShowNewFolderButton = false }; // Set the selected path to the common Sample Pictures folder // if it exists. string initialDirectory = Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.CommonPictures), "Sample Pictures"); if (Directory.Exists(initialDirectory)) { dlg.SelectedPath = initialDirectory; } // Show the dialog and process the dataflow network. if (dlg.ShowDialog() == DialogResult.OK) { // Create a new CancellationTokenSource object to enable // cancellation. cancellationTokenSource = new CancellationTokenSource(); // Create the image processing network if needed. headBlock ??= CreateImageProcessingNetwork(); // Post the selected path to the network. headBlock.Post(dlg.SelectedPath); // Enable the Cancel button and disable the Choose Folder button. toolStripButton1.Enabled = false; toolStripButton2.Enabled = true; // Show a wait cursor. Cursor = Cursors.WaitCursor; } }A főűrlap űrlaptervezőjében hozzon létre egy eseménykezelőt az Click eseményhez a Mégse gombhoz.
Implementálja a ClickMégse gomb eseményét.
// Event handler for the Cancel button. private void toolStripButton2_Click(object sender, EventArgs e) { // Signal the request for cancellation. The current component of // the dataflow network will respond to the cancellation request. cancellationTokenSource.Cancel(); }
A teljes példa
Az alábbi példa az útmutató teljes kódját mutatja be.
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Threading.Tasks.Dataflow;
using System.Windows.Forms;
namespace CompositeImages
{
public partial class Form1 : Form
{
// The head of the dataflow network.
ITargetBlock<string> headBlock = null;
// Enables the user interface to signal cancellation to the network.
CancellationTokenSource cancellationTokenSource;
public Form1()
{
InitializeComponent();
}
// Creates the image processing dataflow network and returns the
// head node of the network.
ITargetBlock<string> CreateImageProcessingNetwork()
{
//
// Create the dataflow blocks that form the network.
//
// Create a dataflow block that takes a folder path as input
// and returns a collection of Bitmap objects.
var loadBitmaps = new TransformBlock<string, IEnumerable<Bitmap>>(path =>
{
try
{
return LoadBitmaps(path);
}
catch (OperationCanceledException)
{
// Handle cancellation by passing the empty collection
// to the next stage of the network.
return Enumerable.Empty<Bitmap>();
}
});
// Create a dataflow block that takes a collection of Bitmap objects
// and returns a single composite bitmap.
var createCompositeBitmap = new TransformBlock<IEnumerable<Bitmap>, Bitmap>(bitmaps =>
{
try
{
return CreateCompositeBitmap(bitmaps);
}
catch (OperationCanceledException)
{
// Handle cancellation by passing null to the next stage
// of the network.
return null;
}
});
// Create a dataflow block that displays the provided bitmap on the form.
var displayCompositeBitmap = new ActionBlock<Bitmap>(bitmap =>
{
// Display the bitmap.
pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
pictureBox1.Image = bitmap;
// Enable the user to select another folder.
toolStripButton1.Enabled = true;
toolStripButton2.Enabled = false;
Cursor = DefaultCursor;
},
// Specify a task scheduler from the current synchronization context
// so that the action runs on the UI thread.
new ExecutionDataflowBlockOptions
{
TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext()
});
// Create a dataflow block that responds to a cancellation request by
// displaying an image to indicate that the operation is cancelled and
// enables the user to select another folder.
var operationCancelled = new ActionBlock<object>(delegate
{
// Display the error image to indicate that the operation
// was cancelled.
pictureBox1.SizeMode = PictureBoxSizeMode.CenterImage;
pictureBox1.Image = pictureBox1.ErrorImage;
// Enable the user to select another folder.
toolStripButton1.Enabled = true;
toolStripButton2.Enabled = false;
Cursor = DefaultCursor;
},
// Specify a task scheduler from the current synchronization context
// so that the action runs on the UI thread.
new ExecutionDataflowBlockOptions
{
TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext()
});
//
// Connect the network.
//
// Link loadBitmaps to createCompositeBitmap.
// The provided predicate ensures that createCompositeBitmap accepts the
// collection of bitmaps only if that collection has at least one member.
loadBitmaps.LinkTo(createCompositeBitmap, bitmaps => bitmaps.Count() > 0);
// Also link loadBitmaps to operationCancelled.
// When createCompositeBitmap rejects the message, loadBitmaps
// offers the message to operationCancelled.
// operationCancelled accepts all messages because we do not provide a
// predicate.
loadBitmaps.LinkTo(operationCancelled);
// Link createCompositeBitmap to displayCompositeBitmap.
// The provided predicate ensures that displayCompositeBitmap accepts the
// bitmap only if it is non-null.
createCompositeBitmap.LinkTo(displayCompositeBitmap, bitmap => bitmap != null);
// Also link createCompositeBitmap to operationCancelled.
// When displayCompositeBitmap rejects the message, createCompositeBitmap
// offers the message to operationCancelled.
// operationCancelled accepts all messages because we do not provide a
// predicate.
createCompositeBitmap.LinkTo(operationCancelled);
// Return the head of the network.
return loadBitmaps;
}
// Loads all bitmap files that exist at the provided path.
IEnumerable<Bitmap> LoadBitmaps(string path)
{
List<Bitmap> bitmaps = new List<Bitmap>();
// Load a variety of image types.
foreach (string bitmapType in
new string[] { "*.bmp", "*.gif", "*.jpg", "*.png", "*.tif" })
{
// Load each bitmap for the current extension.
foreach (string fileName in Directory.GetFiles(path, bitmapType))
{
// Throw OperationCanceledException if cancellation is requested.
cancellationTokenSource.Token.ThrowIfCancellationRequested();
try
{
// Add the Bitmap object to the collection.
bitmaps.Add(new Bitmap(fileName));
}
catch (Exception)
{
// TODO: A complete application might handle the error.
}
}
}
return bitmaps;
}
// Creates a composite bitmap from the provided collection of Bitmap objects.
// This method computes the average color of each pixel among all bitmaps
// to create the composite image.
Bitmap CreateCompositeBitmap(IEnumerable<Bitmap> bitmaps)
{
Bitmap[] bitmapArray = bitmaps.ToArray();
// Compute the maximum width and height components of all
// bitmaps in the collection.
Rectangle largest = new Rectangle();
foreach (var bitmap in bitmapArray)
{
if (bitmap.Width > largest.Width)
largest.Width = bitmap.Width;
if (bitmap.Height > largest.Height)
largest.Height = bitmap.Height;
}
// Create a 32-bit Bitmap object with the greatest dimensions.
Bitmap result = new Bitmap(largest.Width, largest.Height,
PixelFormat.Format32bppArgb);
// Lock the result Bitmap.
var resultBitmapData = result.LockBits(
new Rectangle(new Point(), result.Size), ImageLockMode.WriteOnly,
result.PixelFormat);
// Lock each source bitmap to create a parallel list of BitmapData objects.
var bitmapDataList = (from bitmap in bitmapArray
select bitmap.LockBits(
new Rectangle(new Point(), bitmap.Size),
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb))
.ToList();
// Compute each column in parallel.
Parallel.For(0, largest.Width, new ParallelOptions
{
CancellationToken = cancellationTokenSource.Token
},
i =>
{
// Compute each row.
for (int j = 0; j < largest.Height; j++)
{
// Counts the number of bitmaps whose dimensions
// contain the current location.
int count = 0;
// The sum of all alpha, red, green, and blue components.
int a = 0, r = 0, g = 0, b = 0;
// For each bitmap, compute the sum of all color components.
foreach (var bitmapData in bitmapDataList)
{
// Ensure that we stay within the bounds of the image.
if (bitmapData.Width > i && bitmapData.Height > j)
{
unsafe
{
byte* row = (byte*)(bitmapData.Scan0 + (j * bitmapData.Stride));
byte* pix = (byte*)(row + (4 * i));
a += *pix; pix++;
r += *pix; pix++;
g += *pix; pix++;
b += *pix;
}
count++;
}
}
//prevent divide by zero in bottom right pixelless corner
if (count == 0)
break;
unsafe
{
// Compute the average of each color component.
a /= count;
r /= count;
g /= count;
b /= count;
// Set the result pixel.
byte* row = (byte*)(resultBitmapData.Scan0 + (j * resultBitmapData.Stride));
byte* pix = (byte*)(row + (4 * i));
*pix = (byte)a; pix++;
*pix = (byte)r; pix++;
*pix = (byte)g; pix++;
*pix = (byte)b;
}
}
});
// Unlock the source bitmaps.
for (int i = 0; i < bitmapArray.Length; i++)
{
bitmapArray[i].UnlockBits(bitmapDataList[i]);
}
// Unlock the result bitmap.
result.UnlockBits(resultBitmapData);
// Return the result.
return result;
}
// Event handler for the Choose Folder button.
private void toolStripButton1_Click(object sender, EventArgs e)
{
// Create a FolderBrowserDialog object to enable the user to
// select a folder.
FolderBrowserDialog dlg = new FolderBrowserDialog
{
ShowNewFolderButton = false
};
// Set the selected path to the common Sample Pictures folder
// if it exists.
string initialDirectory = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.CommonPictures),
"Sample Pictures");
if (Directory.Exists(initialDirectory))
{
dlg.SelectedPath = initialDirectory;
}
// Show the dialog and process the dataflow network.
if (dlg.ShowDialog() == DialogResult.OK)
{
// Create a new CancellationTokenSource object to enable
// cancellation.
cancellationTokenSource = new CancellationTokenSource();
// Create the image processing network if needed.
headBlock ??= CreateImageProcessingNetwork();
// Post the selected path to the network.
headBlock.Post(dlg.SelectedPath);
// Enable the Cancel button and disable the Choose Folder button.
toolStripButton1.Enabled = false;
toolStripButton2.Enabled = true;
// Show a wait cursor.
Cursor = Cursors.WaitCursor;
}
}
// Event handler for the Cancel button.
private void toolStripButton2_Click(object sender, EventArgs e)
{
// Signal the request for cancellation. The current component of
// the dataflow network will respond to the cancellation request.
cancellationTokenSource.Cancel();
}
~Form1()
{
cancellationTokenSource.Dispose();
}
}
}
Az alábbi ábrán a gyakori \Sample Pictures\ mappa jellemző kimenete látható.