How To Get Screen Shot Capture in C#
It’s often necessary to programmatically get a screen shot of the desktop and save it to a file. This is pretty easy with C#; we can create a simple method that will save an image of whatever is on the screen or desktop.
Saving a Bitmap Image of the Screen
First make sure you include the System.Drawing.Imaging namespace. Now, all we really have to do is create a new bitmap and use the CopyFromScreen method of the bitmaps Graphics device.
/// <summary> /// Saves a screen capture in the specified image format to a file. /// </summary> /// <param name="filename"></param> /// <param name="format"></param> private void SaveScreenShot(string filename, ImageFormat format) { Bitmap screenShot = CaptureScreenShot(); screenShot.Save(filename, format); } /// <summary> /// Saves a picture of the screen to a bitmap image. /// </summary> /// <returns>The saved bitmap.</returns> private Bitmap CaptureScreenShot() { // get the bounding area of the screen containing (0,0) // remember in a multidisplay environment you don't know which display holds this point Rectangle bounds = Screen.GetBounds(Point.Empty); // create the bitmap to copy the screen shot to Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height); // now copy the screen image to the graphics device from the bitmap using (Graphics gr = Graphics.FromImage(bitmap)) { gr.CopyFromScreen(Point.Empty, Point.Empty, bounds.Size); } return bitmap; }
And that’s really all there is to capturing a screen shot. You can save it to whatever file you would like and in any of the image formats supported by ImageFormat such as PNG or JPEG. Keep in mind if your working in a multidisplay environment you’ll want to be careful which display your targeting. Or perhaps you may want a huge image of all the desktop displays.
You can use the above code simply by calling the SaveScreenShot method with a file name and image format to save to:
//save screen shot in PNG image format SaveScreenShot("MyScreenShot.png", ImageFormat.Png);
With a really small change you can modify the above code to save a screen shot of an arbitrary control instead of the entire desktop display.
Saving a Screen Capture of a Control
/// <summary> /// Saves a screen capture of the specified control to a file. /// </summary> /// <param name="control"></param> /// <param name="filename"></param> /// <param name="format"></param> private void SaveControlShot(Control control, string filename, ImageFormat format) { Bitmap controlShot = CaptureControlShot(control); controlShot.Save(filename, format); } /// <summary> /// Gets a bitmap image of the specified control. /// </summary> /// <param name="control"></param> /// <returns></returns> private Bitmap CaptureControlShot(Control control) { // get control bounding rectangle Rectangle bounds = control.Bounds; // create the new bitmap that holds the image of the control Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height); // copy controls image data to the bitmaps graphics device using (Graphics gr = Graphics.FromImage(bitmap)) { gr.CopyFromScreen(control.Location, Point.Empty, bounds.Size); } return bitmap; }
And you can use this just as easily as the previous screen capture method:
// if "this" is a control, like a form SaveControlShot(this, "MyControlShot.png", ImageFormat.Png);
And there you have it, an example of simple methods for saving a screen shot or an image of a control. I Hope you find this helpful.
April 13, 2009
·
crow ·
11 Comments
Posted in: C#, Programming
Introduction to Multithreading in C#
This article is a very basic introductory tutorial for using multiple threads in C#. I’ll explain what threads are, why you would want to use them, and how to use them. I’ll also show you several examples for creating threads, killing threads, etc.
What’s a Thread?
A computer program is generally very linear. That is, you have a sequence of instructions that get executed one after another in an orderly and predictable fashion. This scenario only affords you one path of execution. Threads allow you to execute multiple paths of code simultaneously. Now, simultaneously in this case does not necessarily mean physically at the same time. Both your operating system and processor must support this for that to be true. Threads are not particular to C#; most modern programming languages such as Visual Basic.Net support the concept of threads.
So Why Do I Need Multiple Threads?
Threading is handy because many programming tasks are asynchronous. That is, I can start the task and go on about my business and when that task is finished it can let me know and I can take action. An example of this would be downloading files from a remote location. I can start downloading three files and when the first is finished I can process it while the others continue to download.
There are numerous other reasons. Consider for instance a long task like sorting a million numbers. If I start that task on the thread that runs the GUI then I couldn’t update my user interface which means I couldn’t respond to user requests like button clicks.
Ok, lets move on to an example of creating a new thread via C#.
Creating a Thread with C#
Creating a thread is easy; we make use of the Thread object from the System.Threading namespace. When we create the thread we must pass it a ParameterizedThreadStart or ThreadStart delegate. This will be the method that gets invoked on the new thread – it’s the starting point. New threads begin life in a stopped state. To make it run we call the Thread.Start method.
Thread myThread = new Thread(MyThreadFunction); myThread.Start(); private void MyThreadFunction() { MessageBox.Show("HI"); }
Congratulations, you’ve created your first thread that runs in parallel with your main thread.
Passing an Argument to the New Thread
You can easily pass an argument to the thread like so:
Thread myThread = new Thread(MyThreadFunction); myThread.Start("HELLO WORLD"); private void MyThreadFunction(object x) { MessageBox.Show(x as string); }
Keep in mind that this is not the best way to pass data to the thread. Since Thread.Start accepts only an object this is not very type safe. Image if we didn’t pass a string or the object didn’t have a ToString method. The best way to accomplish this would be to encapsulate your thread function in a class with data members you could set ahead of time.
Waiting for a Thread to Stop
Now that we have our thread up and running, we may at some point wish to wait for it to complete. This is accomplished with the Thread.Join method. Here is an example for Thread.Join:
myThread = new Thread(MyThreadFunction); myThread.Start("HELLO WORLD"); myThread.Join(); MessageBox.Show("ALL DONE!"); //-elsewhere private void MyThreadFunction(object x) { MessageBox.Show(x as string); }
When the first piece of code executes it will create a new thread that will begin running in MyThreadFunction. After calling myThread.join that thread will go to sleep and stop executing until MyThreadFunction returns. This will happen after you dismiss the message box. Finally, when MyThreadFunction exits and the thread is destroyed, the original thread will continue execution at the next statement and pop its message box.
One thing to watch out for is what happens if the thread function never returns meaning the thread never dies. In this situation you can specify a timeout value in Thread.Join. The method will block for a predetermined amount of time waiting for the thread to terminate. If the thread did not terminate then Thread.Join would return false.
Stopping a Thread
Stopping a thread is simple. You call Thread.Abort on the thread you wish to stop.
myThread.Abort();
This will cause a ThreadAbortException to be raised on the thread you are trying to stop. Now this usually stops the thread. It’s possible that the thread can abort your abort and continue living. There are a few other circumstances that can prevent the thread from aborting.
Sharing Variables
When you have two or more threading running it’s possible that they could be executing at the same time. This can create problems when both threads are trying to read/write to the same variable. You have to synchronize thread access to shared variables. There are many synchronization primitives available to you in C# via the .Net Framework Library such as AutoResetEvent, Monitor, and Mutex. This is a big subject so I will defer it till another post.
Along those same lines here’s a tip: If you create secondary threads they cannot modify controls on your GUI. Only the thread that created a control can modify its properties. You will generate the dreaded illegal cross thread exception. I’ve already posted a brief work around for this problem
So that’s it for my C# threading tutorial. Now you know the basics of how to create a thread, how to kill a thread, how to wait for a thread, and some general threading principles. This is a big subject and I’ve hardly done it justice with this little bit of writing. If there are sufficient interests, I will elaborate on some more advance multithreading techniques that are applicable in all .Net languages – not just C#. I’ll leave you with a small incomplete pro and con list about using multiple threads.
Advantages of Multithreading
- Improved performance – Multiple threads can execute concurrently.
- Streamline application logic – Some tasks are easier to conceptualize this way
- Improves responsiveness of an application – GUI still works under heavy load.
Disadvantages of Multithreading
- Hard to write and debug – Nuff said!!
- Performance impact from synchronizing access to shared variables
- There is a limit to how many threads an operating system can handle efficiently
- Context switching between threads can hurt performance
April 8, 2009
·
crow ·
2 Comments
Posted in: C#, Programming
C# – Dynamically Invoke Web Service At Runtime
Web services have become an integral part of the communications between software over a network. There are a lot of ugly details behind how they work but thankfully C# hide a lot of those gory details. What you need to know is that there is a web service description (WSDL) that describes the available services and the data types they use (via XML).
You can use the WSDL to create types in C# that can communicate with the web service. There are a couple of ways that you can do this. You can generate a proxy class using the WSDL utility in the .NET SDK and add it to your project. You can also download the WSDL file at runtime, create the proxy class, compile it into an assembly, and execute the methods on it. This allows you to dynamically invoke methods from a web service that aren’t known at build time and is the approach I will explore today.
Step 1 – Obtain a ServiceDescriptionImporter
We want to create a ServiceDescriptionImporter object that we can use to generate the web service proxy class. We have to pass to it the WSDL location which is an XML document.
XmlTextReader xmlreader = new XmlTextReader(“MyWebService” + "?wsdl"); ServiceDescription serviceDescription = ServiceDescription.Read(xmlreader); // build an importer, that assumes the SOAP protocol, client binding, and generates properties ServiceDescriptionImporter descriptionImporter = new ServiceDescriptionImporter(); descriptionImporter.ProtocolName = "Soap"; descriptionImporter.AddServiceDescription(serviceDescription, null, null); descriptionImporter.Style = ServiceDescriptionImportStyle.Client; descriptionImporter.CodeGenerationOptions = System.Xml.Serialization.CodeGenerationOptions.GenerateProperties;
Step 2 – Compile an Assembly from the importer
Now that we have the ServiceDescriptionImporter we need to use it to compile a proxy assembly that we can use to communicate with the web service. The assembly will exist in the users’ temporary folder.
// a namespace and compile unit are needed by importer CodeNamespace codeNamespace = new CodeNamespace(); CodeCompileUnit codeUnit = new CodeCompileUnit(); codeUnit.Namespaces.Add(codeNamespace); ServiceDescriptionImportWarnings importWarnings = descriptionImporter.Import(codeNamespace, codeUnit); if (importWarnings == 0) // no warnings { // create a c# compiler CodeDomProvider compiler = CodeDomProvider.CreateProvider("CSharp"); // include the assembly references needed to compile string[] references = new string[2] { "System.Web.Services.dll", "System.Xml.dll" }; CompilerParameters parameters = new CompilerParameters(references); // compile into assembly CompilerResults results = compiler.CompileAssemblyFromDom(parameters, codeUnit); foreach (CompilerError oops in results.Errors) { // trap these errors and make them available to exception object throw new Exception("Compilation Error Creating Assembly"); } // all done.... return results.CompiledAssembly; } else { // warnings issued from importers, something wrong with WSDL throw new Exception("Invalid WSDL"); }
Step 3 – Execute Methods from the Web Service
Finally we have an assembly built from the web service description and now we can invoke methods from it just like any other ordinary assembly we might use. To accomplish this we must use reflection to discover the correct method.
object obj = this.webServiceAssembly.CreateInstance(serviceName); Type type = obj.GetType(); return (T)type.InvokeMember(methodName, BindingFlags.InvokeMethod, null, obj, args);
And there you have it, dynamic invocation of web service methods at runtime. Using this technique you can invoke methods from any arbitrary web service at runtime.
Here is a full example class for dynamically invoking a web service method in C#.
using System; using System.Collections.Generic; using System.Text; using System.Reflection; using System.CodeDom; using System.CodeDom.Compiler; using System.Web.Services; using System.Web.Services.Description; using System.Web.Services.Discovery; using System.Xml; namespace DynamicWebExample { class WebServiceInvoker { Dictionary<string, Type> availableTypes; /// <summary> /// Text description of the available services within this web service. /// </summary> public List<string> AvailableServices { get{ return this.services; } } /// <summary> /// Creates the service invoker using the specified web service. /// </summary> /// <param name="webServiceUri"></param> public WebServiceInvoker(Uri webServiceUri) { this.services = new List<string>(); // available services this.availableTypes = new Dictionary<string, Type>(); // available types // create an assembly from the web service description this.webServiceAssembly = BuildAssemblyFromWSDL(webServiceUri); // see what service types are available Type[] types = this.webServiceAssembly.GetExportedTypes(); // and save them foreach (Type type in types) { services.Add(type.FullName); availableTypes.Add(type.FullName, type); } } /// <summary> /// Gets a list of all methods available for the specified service. /// </summary> /// <param name="serviceName"></param> /// <returns></returns> public List<string> EnumerateServiceMethods(string serviceName) { List<string> methods = new List<string>(); if (!this.availableTypes.ContainsKey(serviceName)) throw new Exception("Service Not Available"); else { Type type = this.availableTypes[serviceName]; // only find methods of this object type (the one we generated) // we don't want inherited members (this type inherited from SoapHttpClientProtocol) foreach (MethodInfo minfo in type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly)) methods.Add(minfo.Name); return methods; } } /// <summary> /// Invokes the specified method of the named service. /// </summary> /// <typeparam name="T">The expected return type.</typeparam> /// <param name="serviceName">The name of the service to use.</param> /// <param name="methodName">The name of the method to call.</param> /// <param name="args">The arguments to the method.</param> /// <returns>The return value from the web service method.</returns> public T InvokeMethod<T>( string serviceName, string methodName, params object[] args ) { // create an instance of the specified service // and invoke the method object obj = this.webServiceAssembly.CreateInstance(serviceName); Type type = obj.GetType(); return (T)type.InvokeMember(methodName, BindingFlags.InvokeMethod, null, obj, args); } /// <summary> /// Builds the web service description importer, which allows us to generate a proxy class based on the /// content of the WSDL described by the XmlTextReader. /// </summary> /// <param name="xmlreader">The WSDL content, described by XML.</param> /// <returns>A ServiceDescriptionImporter that can be used to create a proxy class.</returns> private ServiceDescriptionImporter BuildServiceDescriptionImporter( XmlTextReader xmlreader ) { // make sure xml describes a valid wsdl if (!ServiceDescription.CanRead(xmlreader)) throw new Exception("Invalid Web Service Description"); // parse wsdl ServiceDescription serviceDescription = ServiceDescription.Read(xmlreader); // build an importer, that assumes the SOAP protocol, client binding, and generates properties ServiceDescriptionImporter descriptionImporter = new ServiceDescriptionImporter(); descriptionImporter.ProtocolName = "Soap"; descriptionImporter.AddServiceDescription(serviceDescription, null, null); descriptionImporter.Style = ServiceDescriptionImportStyle.Client; descriptionImporter.CodeGenerationOptions = System.Xml.Serialization.CodeGenerationOptions.GenerateProperties; return descriptionImporter; } /// <summary> /// Compiles an assembly from the proxy class provided by the ServiceDescriptionImporter. /// </summary> /// <param name="descriptionImporter"></param> /// <returns>An assembly that can be used to execute the web service methods.</returns> private Assembly CompileAssembly(ServiceDescriptionImporter descriptionImporter) { // a namespace and compile unit are needed by importer CodeNamespace codeNamespace = new CodeNamespace(); CodeCompileUnit codeUnit = new CodeCompileUnit(); codeUnit.Namespaces.Add(codeNamespace); ServiceDescriptionImportWarnings importWarnings = descriptionImporter.Import(codeNamespace, codeUnit); if (importWarnings == 0) // no warnings { // create a c# compiler CodeDomProvider compiler = CodeDomProvider.CreateProvider("CSharp"); // include the assembly references needed to compile string[] references = new string[2] { "System.Web.Services.dll", "System.Xml.dll" }; CompilerParameters parameters = new CompilerParameters(references); // compile into assembly CompilerResults results = compiler.CompileAssemblyFromDom(parameters, codeUnit); foreach (CompilerError oops in results.Errors) { // trap these errors and make them available to exception object throw new Exception("Compilation Error Creating Assembly"); } // all done.... return results.CompiledAssembly; } else { // warnings issued from importers, something wrong with WSDL throw new Exception("Invalid WSDL"); } } /// <summary> /// Builds an assembly from a web service description. /// The assembly can be used to execute the web service methods. /// </summary> /// <param name="webServiceUri">Location of WSDL.</param> /// <returns>A web service assembly.</returns> private Assembly BuildAssemblyFromWSDL(Uri webServiceUri) { if (String.IsNullOrEmpty(webServiceUri.ToString())) throw new Exception("Web Service Not Found"); XmlTextReader xmlreader = new XmlTextReader(webServiceUri.ToString() + "?wsdl"); ServiceDescriptionImporter descriptionImporter = BuildServiceDescriptionImporter(xmlreader); return CompileAssembly(descriptionImporter); } private Assembly webServiceAssembly; private List<string> services; } }
This C# class can be easily used to invoke web service methods:
WebServiceInvoker invoker = new WebServiceInvoker(new Uri("http://localhost/services/test.php")); string service = “MyService”; string method = “MyMethod”; string[] args = new string[] { “arg1”, “arg2” }; string result = invoker.InvokeMethod<string>(service, method, args);
I’ve put together an example application that you can download to evaluate the class. It allows you to invoke methods from a web service entered on the GUI and see the return value. You can download it here.

I hope you find this useful and if you have any questions or comments be sure to leave them here.
April 8, 2009
·
crow ·
78 Comments
Posted in: Programming
Playing an MP3 or WAV File in C#
Playing an audio file such as an MP3 or WAV is incredibly easy in C#. For WAV files you can use the SoundPlayer class found in the System.Media namespace. Playing an MP3 will require referencing the Windows Media Player COM component.
How to Play a WAV file
To play the WAV file simply create a new SoundPlayer object, set the SoundLocation property to the location of your WAV file, and then use the Play method to play it.
System.Media.SoundPlayer player = new System.Media.SoundPlayer(); player.SoundLocation = "My Wav File.wav"; player.Play();
How to Play an MP3 file
Playing an MP3 with C# is just as easy as playing a WAV except that it requires you to use the Window Media Player COM component. So first, add a reference to wmp.dll, which you can find in the System32 directory. Here is an example of how to play an MP3 file:
WMPLib.WindowsMediaPlayer wplayer = new WMPLib.WindowsMediaPlayer(); wplayer.URL = "My MP3 file.mp3"; wplayer.controls.play();
So there you have it; a simple example of how to play an MP3 and WAV file using C#. I hope you find it useful. If you have any questions feel free to ask.
April 5, 2009
·
crow ·
14 Comments
Posted in: C#
How To Extract A Zip File With C#
The .Net Framework Class Libraries are great and allow you to manipulate many different file formats. Unfortunately they seemed to have left out support for standard Zip files. Thankfully our good friends over at ICSharpCode have released an awesome little library for handling Zip files called the SharpZipLib.
The library is very simple to use and supports several formats including:
- Zip
- GZip
- Tar
- BZip2
Using SharpZipLib
Extracting a file with SharpZipLib is really quite simple. First you create a ZipInputStream from an existing FileStream to the zip file.
ZipInputStream zinstream = new ZipInputStream(File.OpenRead(source));
Next you read the entries from the zip file, which could be either a file or directory.
ZipEntry theEntry; while ((theEntry = zinstream.GetNextEntry()) != null) { // if theEntry is a directory then create it on disk // otherwise it’s a file so read from zinstream just like // you would any other file }
The ZipEntry represents either a file or directory that must be read and reproduced in the target directory where you are extracting the files to. GetNextEntry will continue to return either the next directory or the next file in the Zip file until no more exist. Here is a complete example of extracting all files (while maintaining directory structure) to a local folder.
The Extraction Function
public static int ExtractAll(string source, string destination) { ZipInputStream zinstream = null; // used to read from the zip file int numFileUnzipped = 0; // number of files extracted from the zip file try { // create a zip input stream from source zip file zinstream = new ZipInputStream(File.OpenRead(source)); // we need to extract to a folder so we must create it if needed if (Directory.Exists(destination) == false) Directory.CreateDirectory(destination); ZipEntry theEntry; // an entry in the zip file which could be a file or directory // now, walk through the zip file entries and copy each file/directory while ((theEntry = zinstream.GetNextEntry()) != null) { string dirname = Path.GetDirectoryName(theEntry.Name); // the file path string fname = Path.GetFileName(theEntry.Name); // the file name // if a path name exists we should create the directory in the destination folder string target = destination + Path.DirectorySeparatorChar + dirname; if (dirname.Length > 0 && !Directory.Exists(target)) Directory.CreateDirectory(target); // now we know the proper path exists in the destination so copy the file there if (fname != String.Empty) { DecompressAndWriteFile(destination + Path.DirectorySeparatorChar + theEntry.Name, zinstream); numFileUnzipped++; } } } catch (Exception) { throw; } finally { zinstream.Close(); } return numFileUnzipped; }
And the DecompressAndWrite method:
private static void DecompressAndWriteFile( string destination, ZipInputStream source ) { FileStream wstream = null; try { // create a stream to write the file to wstream = File.Create(destination); const int block = 2048; // number of bytes to decompress for each read from the source byte[] data = new byte[block]; // location to decompress the file to // now decompress and write each block of data for the zip file entry while (true) { int size = source.Read(data, 0, data.Length); if (size > 0) wstream.Write(data, 0, size); else break; // no more data } } catch(Exception) { throw; } finally { if( wstream != null ) wstream.Close(); } }
Pretty neat huh? I love how simple it is.
If those methods are placed into a class called Zip, then extracting a Zip file is as easy as:
Zip.ExtractAll(myZipFile, myDestinationFolder);
I’ve put together a sample project that uses the SharpZipLib to extract the contents of a zip file. It basically just allows you to select the zip file and the destination from a form and uses the methods above. You can find it below.
Let me know if you find this useful or need any help!!!
April 3, 2009
·
crow ·
One Comment
Posted in: General
Documentation Template Via Visual Studio Macro
Consistency is the key when working on computer software, especially if you are developing a large system with multiple programmers. You should be consistent with the layout and format of your source code. Unfortunately this can be difficult to achieve when time is precious – and isn’t it always. However Visual Studios macro system makes it a breeze to automate this task with little to no work. Here is a simple way to implement this in C#.
What I would like to be able to do is execute a simple macro and see a dialog box that lets me enter information specific to the source file I am working with. That information will then be inserted into the file using a predefined template. The dialog will look something like this:

To accomplish this task we need to things; a .Net class library that implements the dialog and the macro to launch it and interact with Visual Studio using its automation model.
Read the rest of this post »
April 2, 2009
·
crow ·
4 Comments
Posted in: General
C# – Auto Increment Assembly Version Number
When it comes to developing software one thing that I find is always a pain is keeping track of and assigning version numbers. I’ve been writing a lot of stuff in C# lately and I’ve found a rather elegant way to achieve dynamic build numbers that automatically update each time you build the application.
In the .Net world each assembly receives its own version number of the form “a.b.c.d”, where each letter represents the major, minor, build, and revision number respectively. The goal here is to allow me to set the major and minor numbers manually, have the build number be the date stamp indicating the date the build took place, and have the revision number increment each build. The revision number should be reset each time the build number changes (i.e. the date of the build).
To accomplish this task we must call on Microsoft’s msbuild program. Msbuild is the build tool for .Net languages and is essentially like make from the Unix/Linux world. It turns out Microsoft has already created a task for msbuild to do what I need. It’s called “AssemblyInfo Task” and you can find it here.
In order to get the AssemblyInfo Task up and running first run the installer located in the download. When prompted install the task into the GAC. Next create a new project in Visual Studio. Copy the file
Microsoft.VersionNumber.targets from
“\Program Files\MSBuild\Microsoft\AssemblyInfoTask”
into your project directory.
Now, open your .csproj file in a text editor (it’s just an XML file). Look toward the end of the file and find the line
<Import Project=”$(MSBuildBinPath)\Microsoft.CSharp.targets” />.
Just below this line add:
<Import Project=”$(SolutionDir)\extra\tools\msbuild\Microsoft.VersionNumber.targets” />.
This will make sure the AssemblyInfo Task is run each time you build your project.
Finally rebuild your project. SUCCESS! No Wait. Not quite. You are probably looking at a warning such as: warning CS1607: Assembly generation — The version ’1.0.090331.00′ specified for the ‘file version’ is not in the normal ‘major.minor.build.revision’ format.
Read the rest of this post »
April 1, 2009
·
crow ·
7 Comments
Posted in: Programming
C# GUI Cross Thread Exceptions
It has been a while since I’ve posted anything here and I’ve been collecting thoughts and ideas that need to be spewed out over a few posts.
Any of you who have spent time programming in a GUI environment have undoubtedly ran across the dreaded illegal cross thread operation when modifying a control from a secondary thread. You simply cannot modify the properties of a control unless you are executing in the context of the thread that created it. This goes for .Net based languages such as C# as well as others such as Java.
Subtle bugs can be introduced into your software because it’s easy to forget about this or just flat out not know your violating the rule. Of course, an exception isn’t generated till after you have deployed your application and your boss pays you a visit.
The fix on the other hand is incredibly easy and it’s surprising how many developers I see doing this the hard way. You can simply pass an anonymous delegate to the Invoke method of the control you wish to modify.
Here is a simple example. It has a form that contains a button named button1 and a label called label1. When you click the button the text of the label will change.
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Threading; namespace WindowsFormsApplication1 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { // this is the thread that will change the label text Thread myThread = new Thread(ThreadFunction); myThread.Start(); } private void ThreadFunction() { this.label1.Invoke((MethodInvoker)delegate() { // when we get here we are now in the context of the primary user interface // thread, hence we can modify all of it's controls this.label1.Text = "Hello New Label"; }); } } }
The above code works great but it still puts the responsibility on the programmer to understand ahead of time if he will be updating a control from a secondary thread. A more efficient pattern would place the code that modifies the control into its own method and then let the method determine if an Invoke is required.
Read the rest of this post »
March 30, 2009
·
crow ·
9 Comments
Posted in: Programming
WP-Syntax Test
Just wanted to check out the WP-Syntax plugin and see how it works/looks.
#include <stdio.h> #include <stdlib.h> int main( void ) { printf( "HELLO WP-Syntax\n" ); return 0; }
February 8, 2009
·
crow ·
One Comment
Posted in: General
Welcome!!
Welcome to Crows Programming!
This site is dedicated to my various rants and raves, mostly related to computer programming and related technologies.
I look forward to hearing feedback from all of you on my thoughts and ideas!
~Crow–
February 6, 2009
·
crow ·
No Comments
Posted in: General
